As a variant on the fizzbuzz concept, and as an exercise for learning JavaScript, HTML5, and CSS (I know none of them very well).
The regular fizzbuzz is somewhat tired, but having a web-based, visualizable output seems to be useful, and being able to adjust the inputs at will, allows you to see the impact of how the modulo changes.
var fizzLoaded = false;
var fizzDiv, fizzFrom, fizzTo, fizzPlayers;
function fizzLoad() {
if (fizzLoaded) {
return;
}
fizzLoaded = true;
var fizzForm = document.getElementById('fizzbuzz');
fizzFrom = document.getElementById('rangeFrom');
fizzTo = document.getElementById('rangeTo');
fizzPlayers = [
document.getElementById('frodo'),
document.getElementById('sam'),
document.getElementById('merry'),
document.getElementById('pippin'),
document.getElementById('bilbo')
];
fizzDiv = document.getElementById('fizzOut');
}
function restrictRange() {
var rFrom = parseInt(fizzFrom.value);
var rTo = parseInt(fizzTo.value);
fizzTo.min = rFrom;
fizzFrom.max = rTo;
}
function validateValues() {
var rFrom = parseInt(fizzFrom.value);
var rTo = parseInt(fizzTo.value);
if (rTo < rFrom) {
alert("Illegal range from " + rFrom + " to " + rTo);
return false;
}
for (var i = 0; i < fizzPlayers.length; i++) {
var val = parseInt(fizzPlayers[i].value);
if (val < 0 || val > 100) {
alert("Illegal value " + val + " for player " + fizzPlayers[i].id);
return false;
}
}
return true;
}
function capitaliseFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
function fizzing() {
fizzLoad();
restrictRange();
if (!validateValues()) {
fizzDiv.innerHTML = "Illegal inputs";
return;
}
var table = "";
var rFrom = parseInt(fizzFrom.value);
var rTo = parseInt(fizzTo.value);
var active = [];
var actfact = [];
var actname = [];
var player;
for (var i = 0; i < fizzPlayers.length; i++) {
player = fizzPlayers[i];
var val = parseInt(player.value);
if (val != 0) {
active.push(player);
actfact.push(parseInt(player.value));
actname.push(capitaliseFirstLetter(player.id));
}
}
table += "<table>\n";
table += " <tr><th>Value</th><th>Message</th></tr>\n";
for (var i = rFrom; i <= rTo; i++) {
var msg = "";
for (var p = 0; p < active.length; p++) {
if (i % actfact[p] == 0) {
msg += actname[p];
}
}
if (msg == "") {
msg = "" + i;
}
table += " <tr><td>" + i + "</td><td>" + msg + "</td></tr>\n";
}
table += "</table>\n";
fizzDiv.innerHTML = table;
}
h1 {
clear: left;
}
hr {
clear: left;
}
label {
display: inline-block;
float: left;
clear: left;
width: 150px;
text-align: left;
}
input {
display: inline-block;
float: right;
text-align: right;
padding-left:10px;
width: 50px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>FizzBuzz</title>
<link rel="stylesheet" href="fizzbuzz.css">
<script src="fizzbuzz.js" type="text/javascript"></script>
</head>
<body>
<h1>Config</h1>
<form id="fizzbuzz">
<fieldset id="fizzControl" oninput="fizzing();">
<label>Range From<input id="rangeFrom" type="number" min="1" max="100" value="1" required></label>
<label>Range To<input id="rangeTo" type="number" min="1" max="1024" value="100" required></label>
<div id="players" >
<label>Frodo<input id="frodo" type="number" min="0" max="100" value="3" required></label>
<label>Sam<input id="sam" type="number" min="0" max="100" value="5" required></label>
<label>Merry<input id="merry" type="number" min="0" max="100" value="0" required></label>
<label>Pippin<input id="pippin" type="number" min="0" max="100" value="0" required></label>
<label>Bilbo<input id="bilbo" type="number" min="0" max="100" value="0" required></label>
</div>
</fieldset>
</form>
<hr>
<h1>Output</h1>
<div id="fizzOut" >Change a value to get output (a snippet thing)
<script>fizzing();</script>
</body>
</html>
I have a number of concerns here that have frustrated me, and I am sure there are better ways to accomplish them...:
CSS:
I tried very hard to isolate the formatting/style from the HTML, but....
- The alignment of the input controls required
left: clear
to get each one on its line - I had to specify the width of the labels
- similarly,
h1
andhr
both neededleft:clear
HTML:
I worry that I had to add the script section to the end to 'initialize' the output. Note that this works well on my server, but, on stack snippets, you have to change an input value to get the output updated.
Are there other problems with the HTML, it seems simple enough....
JavaScript:
This is where I imagine there is much to say, I am sure there are bad practices. Things that frustrate me especially are:
- I was not able to get
for (player in fizzPlayers) ...
to work, the player would always beundefined
. I was forced to do things likefor (var i = 0; var ...)
and then reference back in to thefizzPlayers
array. - I use globals, but limited them to just a few. I missed something there, I know, there must be a way to declare the document lookups just once, without resorting to globals.
In addition to those areas where I struggled, and where I am pretty sure there must be better ways, are there other items I got wrong?
Are there any I got right?
2,3,5,7,11
results in a kind of crude prime number sieve. \$\endgroup\$