Javascript Challenge: Lotto Number Generator

Matthias Reuter's picture

The German lottery currently holds a jackpot of about 30 million Euro. A friend of mine took the bait and participated yesterday. Since he is a software developer, he wrote a small program to get him six random numbers in the range of 1 and 49.

Well, it's not difficult to write such a programm. The challenge is to do so in little bytes. So I challenge you:

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.

To participate in this challenge, simply post your solution as a comment.

Spoiler warning On the next page I describe the steps I took for my solution. Don't read if you want to submit your own.

Comments

Anonymous's picture

for(var n=[],i=0;++i<50;n.push(i));for(;--i>6;n.splice(i*Math.random()|0,1));return n

Cheers, Stephan

Anonymous's picture

How about skipping push and assigning directly?

- n.push(i)
+ n[i-1]=i

1 char saved.

Anonymous's picture

for(n=[],i=0;i<49;n[i++]=i);for(;i>6;n.splice(i--*Math.random()|0,1));return n

78 characters (7 characters shorter):
-removed 'var'
-replaced push with n[i++] (and removed ++ from i++<50)
-50 becomes 49
-moved the -- (could use --i>5, but it's better for readability this way)

too bad you can't do 49>n[i++]=i as it would have shaved off another character

Aleksander

Anonymous's picture

for(n=[],i=0;i<49;n[i++]=i);for(;i>6;n.splice(i--*Math.random(),1));return n

76 chars
-call to floor is not needed.

Anonymous's picture

for(n=[],i=0;i<49;n[i++]=i);for(;i>6;n.splice(i--*Math.random(),1));return n

76 characters
-no floor needed for splice argument

Aleksander

Matthias Reuter's picture

removing var leads to global variables, which was prohibited by the rules.

So this is no valid solution.

Christian Harms's picture

A small pice in an other language: I have added the needed import to the effective codesize: 'import random\n\ta=range(1,49)\n\twhile len(a)>6:a.remove(random.choice(a))\n\treturn a' - then becomes 81 bytes.

  1. import random
  2. def lottoNumbers():
  3.     a=range(1,49)
  4.     while len(a)>6:a.remove(random.choice(a))
  5.     return a

Anonymous's picture

return [1,2,3,4,5,6];

Oh, is it supposed to be different every time?

return [1,2,3,4,5,5+Math.random()*10|0];

See where I'm going with this? Please define your terms. Did you mean a uniform probability distribution over {(a,b,c,d,e,f) | 1 <= a < b < c < d < e < f <= 49}?

Matthias Reuter's picture

When in doubt use your common sense :-)

To clarify: Yes, I mean a uniform probability distribution. Would you use a lotto number generator, if only one number was randomly generated?

Anonymous's picture

Here's 76 bytes(!) using an algorithm that decides randomly whether to include each number from 1 to 49, then checks to see if there were 6 of them. The outer loop seems to run about 7 times on average, so not too bad.

for(;n^6;)for(var a=[],i=0,n;++i<50;)n=Math.random()<.1?a.push(i):n;return a

The probability distribution is correct, and no global variables are created. I think this meets all the criteria.

Note that "push" returns the new length of the array, and "n^6" essentially means "n!=6".

-- DavidG

Anonymous's picture

@DavidG: what is the initial value of n supposed to be?

Matthias Reuter's picture

it's undefined. In a function, Javascript first generates all variables, no matter where they're declared. If no value is given, the value is undefined.

undefined^6 is 6, which converts to true in the outer for-loop

Anonymous's picture

I'll see your 76 bytes and raise you 75 bytes.

for(;n^6;)for(var a=[],i=0,n=0;++i<50;)Math.random()<.1?a[n++]=i:0;return a

Also, this will not cause an undefined error for 0.6% of the calls of the function, as your entry seems to do. Or am I wrong on this?

--Stephan

Matthias Reuter's picture

Wow.

My first thought was: n is global, but no, it's not. My second thought was: what the f*** is happening here? It took me a while to understand what the algorithm does. My third thought was: That's not uniformly distributed. But it is.

So this algorithm meets all the criteria.

Anonymous's picture

anyone cares to dissect this one? i'm still unsure why the values are unique

Anonymous's picture

83 bytes: for(var n=[],i=0;++i<50;n[i-1]=i);for(;--i>6;n.splice(i*Math.random(),1));return n

(1) Splice will automatically convert the first argument to an integer, so floor is not needed. (2) n[i-1]=i can work instead of n.push(i). (3) last return needs no semi-colon.

Matt's picture

  1. r=function(){return Math.random()*50|1};return [r(),r(),r(),r(),r(),r()]

72 bytes

Christian Harms's picture

This simple solution doesn't check for doubles!

Matt's picture

Yeah, turns out I have trouble with this whole "reading comprehension" thing.

I also created a global var and the values aren't in ascending order.

Anonymous's picture

return (Math.random()+"").substr(2).match(/\d{2}/g).splice(0,6).sort().map(function(a){Math.ceil(a/2)})

Not the smallest but fun to write. Doesn't check for dups and not sure the range is correct.

@mpr312

Anonymous's picture

Should be even longer, forgot a return

return (Math.random()+"").substr(2).match(/\d{2}/g).splice(0,6).sort().map(function(a){return Math.ceil(a/2)})

@mpr312

Anonymous's picture

for(var n=[],i=6,r;i;r=Math.random()*49|1,n[-r]?0:n[--i]=n[-r]=r);return n

74 bytes. Fails on the sorting, but c'mon – it's a lottery ;-).

— hzr

Anonymous's picture

in firefox. 48bytes

[0,0,0,0,0,0].map(function() Math.random()*50|1)

Anonymous's picture

interesting how the lambda expression makes it more readable.

Anonymous's picture

42
[,,,,,,].map(function()Math.random()*50|1)

Anonymous's picture

This is not ECMA-262. Play by the rules.

Christian Harms's picture

Hmmmm, nice - but it's not sorted and map not part of the of ECMA-262 definition.

marcelduran's picture

They are not the smallest but they're in a single line (jQuery-like) using features of ECMA-262 only.

This one has 204 bytes (211 including return) and has no repetitions:

new Array(7).join(',x').replace(/x/g,function(){Array.a=Array.a||{};var x;while((x=Math.random()*50|1)in Array.a);Array.a[x]=1;return x}).slice(1).split(',').sort(function(a,b){delete Array.a;return a-b})

Note: I augmented Array by adding an object to it but removed it later, so no global vars added.

This one has 127 bytes (134 including return) and might have repetitions:

new Array(7).join(',x').replace(/x/g,function(){return Math.random()*50|1}).slice(1).split(',').sort(function(a,b){return a-b})

marcelduran's picture

even smaller:

no dupes: 192 or 199 w/ 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})

w/ dupes: 115 or 122 w/ return

[0,0,0,0,0,0].join().replace(/0/g,function(){return Math.random()*50|1}).split(',').sort(function(a,b){return a-b})

Anonymous's picture

I got 72 bytes with an algorithm that memoizes the already chosen numbers.

var a=[],r=n=0;for(;++n<7;a[r]=r)while(a[r=Math.random()*49|1]);return a

The array is not consecutively indexed, but that shouldn't matter, because it is in order and still has only 6 elements.

Anonymous's picture

That defines a variable n in the global scope. Also, it has more than 6 elements. Exactly 6 elements are not undefined, but there are more than 6 nonetheless.

Anonymous's picture

New algorithm: 65 bytes

for(var v=[],m=6,n=49;m;--n)Math.random()*n>m?0:v[--m]=n;return v

Looping until all numbers have been "found", checking numbers 49 to 1 one by one, updating probabilities for each number found/not found.

The probability of the next unchecked number is a number chosen by the lottery is P(number) = m / n where n are the number of unchecked numbers and m are the number of selected numbers left.

JavaScript Challenge Revisited: Lotto Number Generator in Ch's picture

[...] 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 [...]

Forfeit game - coding contest since 50 years | united-coders's picture

[...] older articles (javascript lotto generator or articles with code puzzles tag), here on united-coders.com we linked articles and got comments [...]

Anonymous's picture

So in lay man terms.. How do I win the lottery???