Matthias Reuter from United Coders proposed a JavaScript Challenge: A Lotto Number Generator which the rules follow:
Write a JavaScript function that generates random lotto numbers. This function has to return an array of six different numbers from 1 to 49 (including both) in ascending order. You may use features of ECMA-262 only, that means no Array.contains and stuff. You must not induce global variables. The function has to look like this
var getRandomLottoNumbers = function () {
// your implementation here
};
Minify your function using JSMin (level aggressive) and count the bytes between the outer curly braces.
It might look simple but it turns out to be an interesting challenge considering there’s a bunch of ways to solve it where the length of the minified final implementation is the main concern: the smaller the better. He describes his solution and invites others to post their solutions as comments. His final solution for such challenge has 86 bytes:
var n=[],i=0;for(;++i<50;)n.push(i);for(;--i>6;)n.splice(i*Math.random()|0,1);return n
Some readers wrote even smaller solutions such as:
return [,,,,,,].map(function()Math.random()*50|1)
However this one is by far the smallest, 49 bytes only, it is invalid because it doesn’t fulfill the rules for the following reasons:
-
map
is not part of ECMA-262 specification -
[,,,,,,]
is inconsistent across browsers, IE would create an array of 7undefined
values - it’s not in ascending order
- may contain duplicated values So far the smallest solution that fulfills all the rules has 65 bytes:
for(var v=[],m=6,n=49;m;--n)Math.random()*n>m?0:v[--m]=n;return v
Revisiting
I’ve also contributed with my solution but with another fashion way: Using a single line chaining solution, i.e. no semi-colons separating statements, like: return a().b.c().d.e()
My solution has 200 bytes:
return [0,0,0,0,0,0].join().replace(/0/g,function(){Array.a=Array.a||{};var x;while((x=Math.random()*50|1)in Array.a){}Array.a[x]=1;return x}).split(',').sort(function(a,b){delete Array.a;return a-b})
It’s not the smallest compared to the other solutions but it does fulfill the rules and is in a single line chaining. It might be a little obscure for some but I will break it down into smaller peaces:
return
[0,0,0,0,0,0] // creates an array with 6 positions filled with 0's
.join() // converts the array into string: "0,0,0,0,0,0"
.replace(/0/g, // replaces all 0's in the string using the following function
function () {
Array.a = Array.a || {}; // augments Array with an object property only once
var x; // variable to store a random number
while ( // while condition: assures no dupes
(x = // assigning a value to x:
Math.random() * 50 | 1 // generates a random number times 50 or 1 (when 0)
) in Array.a // checks if x isn't in the augmented Array object
) {} // empty block for while statement
Array.a[x] = 1; // adds number as property into Array object
return x // replaces the "0" found by the random x number
}
) // end of replace function
.split(',') // converts string into array of strings using comma as separator
.sort( // sorts the array using the following compare function
function (a, b) { // elements to be compared
delete Array.a; // restores Array, removing previously augmented property
return a - b // < 0 then a < b; = 0 then a = b; > 0 a > b
}
) // end of sort, a sorted array is returned
I also invite you to post your single line chaining solution as a comment. Happy chaining. ;-)