Here's an arithmetical puzzler for you StackOverflowers. I'm working on a JS game that'll allow someone to enter their name and will generate another name based on what they enter. Sort of like this. Basically every time someone enters a particular string, I want to generate the same other string by taking items from a list.
So I have an array of words, numbering 20 in this example
"nouns": [
"Nitwit",
"Cretin",
"Village Idiot"
// ..
]
When the user inputs their name, I convert each ASCII alphabetic character to a digit. I'm going to add up all the resulting digits and use the total to select one of the words from my array.
// Convert alpha chars to numerical equivalents
function str2num (mystr) {
mystr = mystr.toUpperCase();
var conv = [],
l = mystr.length,
regex = /^[A-Za-z]+$/;
for (var i = 0; i < l; i++) {
if (regex.test(mystr.charAt(i))) {
conv.push(mystr.charCodeAt(i) - 64);
}
}
var c = conv.length,
sum = 0;
for (var j = 0; j < c; j++) {
sum += conv[j];
}
return sumDigits(sum);
}
Since there are only 20 elements in the word array, I always want the sum to be less than 20. So if it's equal or greater than 20, I want to add up its digits again. This is how I'm currently doing it.
// Recursively add digits of number together
// till the total is less than length of word list
function sumDigits (number) {
var listLength = adjectives.length;
var sum = number % listLength;
if (number > listLength) {
var remainder = Math.floor(number / 10);
sum += sumDigits(remainder);
}
if (sum > listLength) {
sum = sumDigits(sum);
}
return sum;
}
And when I've got a result below 20, I return the value of nouns[sum]
to the user. This code pretty much works - the resulting sum is always below the maximum allowed. But the result isn't very random - it seems that I'm getting a disproportionate number of sums in the lower end of the 0 to 20 range. I don't want users to keep seeing words from the beginning of my list. Is there any change I can make to sumDigits that will ensure an even spread of results? Or is this already correct? (I've done this JSFiddle to demo what I'm talking about.)