
Function inside a for loop: Generator function? Help on small project.
Hey everyone, this is my first post. I have finished a JavaScript tutorial on codeacademy.org’s site a few days ago. It took me a few months or so to complete it.
I figure now I have the basic understanding of Object Oriented Programing to dive into a small project I have been thinking of doing. Plus I learn best diving into whatever it is I am doing.
I am making a basic numbers generator for U.S. lottery called PowerBall. I have practiced working with jQuery before, but this I want to make from strait JavaScript (no libraries involved).
The generator is pretty simple really,5 white balls are picked at random ranging 0159, as well as a red ‘poweball’ ranging 0135.
I have gotten to the point where I have the basic HTML template and a button that runs a function on an onclick, but I can only get one result for the white ball #.
I have not looked at the PowerBall value yet as I figure it should be easy for one value and .push() the key to the assigned array.
I have only been working on the five numbers and I think of multiple ways it could be solved.I want to keep DRY (Don’t Reduplicate Yourself) and DIE (Duplication Is Evil) to a minimum. Unfortunately, I haven’t even got a repetitive block of js to work:
var whiteBall1 = Math.floor(Math.random() * 59 + 1);
var whiteBall2 = Math.floor(Math.random() * 59 + 1);
var whiteBall3 = Math.floor(Math.random() * 59 + 1);
var whiteBall4 = Math.floor(Math.random() * 59 + 1);
var whiteBall5 = Math.floor(Math.random() * 59 + 1);
and the print the variables.
I want to make an array of what the values should be. A for lop would then calculate for each key in the array:
var whiteBallArray = [i,i,i,i,i];
for (var i = 0; i < whiteBallArray.length; i++) {
var n = Math.floor(Math.random() * 59 + 1);
document.write(whiteBallArray[i]);
I did some further research and I found a blog about generator functions? I tried but no luck:
var whiteBallArray = [i,i,i,i,i];
var i = 0;
(function(whiteBallArray) {
return function() {
i = Math.floor(Math.random() * 59 + 1);
}
})(i);
I hope I gave enough information on here for the problem. Here is a pastebin link of the entire thing if you want to try and work it out.Find Powerballjs and Powerballhtml..... So far I got the for loop to work, but the array shows the same value for all five keys...
I am using chome browser btw.
Thanks!

Create an array of all available balls, then randomly transfer the required amount to a new array:
Code:
<script type='text/javascript'>
var selectedBalls = [],
ballSet = [],
range = 59,
ballCount = 5,
powerBall;
for( var i = 0; i < range; i++ )
ballSet[ i ] = i + 1;
for( var i = 0; i < ballCount; i++ )
selectedBalls.push( ballSet.splice( Math.floor( Math.random() * ballSet.length ), 1 ) );
selectedBalls.sort( function( a, b ){ return Number( a ) < Number( b ) ? 1 : 1; } );
powerBall = Math.floor( 1 + Math.random() * 35 ) ;
alert( selectedBalls + '\n\nPowerball = ' + powerBall );
</script>

hello logic ali
Adding another solution to show others that with any programming language there are multiple ways to achieve a result.
This will replace existing JavaScript and work with buttons...
Code:
var white = [];
function gen() {
var num, red;
white.length = 0;
while (white.length < 5) {
num = Math.floor(Math.random() * 59) + 1;
if (white.indexOf(num) < 0) {
white.push(num);
}
}
do {
red = Math.floor(Math.random() * 35) + 1;
} while (white.indexOf(red) > 1);
white.sort(function (a, b) {return a  b; });
document.getElementById("gen_num").innerHTML = white + ' + red ' + red;
}

Originally Posted by grumpyOleMan
Adding another solution to show others that with any programming language there are multiple ways to achieve a result.
Code:
do {
red = Math.floor(Math.random() * 35) + 1;
} while (white.indexOf(red) > 1);
I can't accept that algorithm, because wasted calls to Math.random result in an imbalance that compromises the randomness of the result.

Originally Posted by Logic Ali
I can't accept that algorithm, because wasted calls to Math.random result in an imbalance that compromises the randomness of the result.
Interesting call....
Considering the solution requires six unique numbers (an assumption) and taking into account how effective JavaScript’s random number generator is the algorithm may only deteriorate the effectiveness of the result marginally.
Again I was only putting forward an alternate solution to generate the required set and sorry if that pesky algorithm upsets you so.

Good solutions ideas. Thank you so much! @Logic Ali  I took you example and transcribed it in a simpler context. You gave me a chance to review what I have learned about JavaScript such as the ternary operator and sort(), .push(), and splice() methods. Thank You again. Here is an easier (at least me me) version of it and yes a put a while loop in there instead of another for... because I wanted to look like I knew what I was doing
This is an external js file so I excluded the
HTML Code:
<script></script>
tags.
Code:
/* numbers is all values whiteballs and powerball.
Ab is an empty array for Allballs.
rB is the powerball value.
*/
wB are how any white balls there are.
var numbers = [];
Ab = [];
wB = 5;
rB = Math.floor(Math.random() * 35 + 1);
for ( i = 0; i < wB; i++ ) {
Ab.push( Math.floor( Math.random() * 59 + 1) );
}
Ab.push(rB);
var i = 0;
while ( i < Ab.length ) {
numbers +='<li>' + Ab[i] + '</li>';
i++;
}
function gen() {
document.getElementById("gen_num").innerHTML= numbers;
};
It is kind of repeating how variables Ab and numbers are the same thing, but it was the only solution to add HTML tags between the keys.

Originally Posted by Tryah85
Good solutions ideas. Thank you so much! @Logic Ali  I took you example and transcribed it in a simpler context. You gave me a chance to review what I have learned about JavaScript such as the ternary operator and sort(), .push(), and splice() methods. Thank You again. Here is an easier (at least me me) version of it and yes a put a while loop in there instead of another for... because I wanted to look like I knew what I was doing
Your code does nothing to prevent duplicates, which you said you wanted to do. Here's a small change to your code that removes duplicates.
Because all values are consecutive, instead of picking from an array of available values, we can test for an existing duplicate and keep moving along to the next available value, starting back at the beginning if needed. Requires support for Array.indexOf:
Code:
<!DOCTYPE HTML>
<html>
<head>
<title>Test Page</title>
<meta httpequiv="contenttype" content="text/html; charset=iso88591">
</head>
<body>
<span id='gen_num'></span>
<script type='text/javascript'>
/* numbers is all values whiteballs and powerball.
Ab is an empty array for Allballs.
rB is the powerball value.
wB are how any white balls there are.
*/
var numbers = [],
Ab = [],
wB = 5,
range = 59,
ball,
rB = Math.floor(Math.random() * 35 + 1);
for ( var i = 0; i < wB; i++ )
{
ball = Math.floor( Math.random() * range + 1);
while( Ab.indexOf( ball ) != 1 )
ball += ( ball < range ? 1 : (ball) + 1 );
Ab.push( ball );
}
Ab.push(rB);
var i = 0;
while ( i < Ab.length ) {
numbers +='<li>' + Ab[i] + '</li>';
i++;
}
function gen() {
document.getElementById("gen_num").innerHTML= numbers;
};
gen();
</script>
</body>
</html>

An other method consists to randomly generate a new rank from the remaining choices (witch numbers are decreasing : 59, 58, 57, 56 and 55). Then we have only (not to count the already made choices) to increase our random rank for the preceding choices with a lower rank ! An object is also usefull to avoid an indexOf witch is recent for arrays (and do not work for IE8).
Code:
<body>
<p id='gen_num'></p>
<script type='text/javascript'>
(function(){
var rsp='', objAllB = {}, nmbAllB = 5, range = 59, ball,
ball = Math.floor(Math.random() * 35 + 1);
rsp +='White ball : ' + ball + ' ';
for ( var i = 0; i < nmbAllB; i++ ){
ball = Math.floor( Math.random() * range + 1);
for (j in objAllB) if (j<=ball) ball++;
objAllB[ball]=true;
range;
}
rsp+='<br>Power Balls :';
for (i in objAllB) rsp +=' '+ i;
document.getElementById("gen_num").innerHTML= rsp;
}());
</script>
</body>
Last edited by 007Julien; 02082013 at 08:21 AM.

wow guys. I am impressed. I should have made it clearer at first on the beginning of the thread I just wanted to concentrate on the JS code not having repetition. In other words, I do not want a new variable for each picked number.
I really do not mind if any number in the array have the same number if it randomly happens to be the case. I have seen the same numbers before on the same ticket in real life.
The way I understand Logic Ali is from the while loop added, I transcribe it as:
Code:
while index array value of ball is not equal to 1 < when this is true (confusing)
do this:
if ball is less than range, true: Else negative array index of ball add one;
then add this new arrangement to Ab
basically this block checks whether the previous number is not the same as the current number generated.
This would be better in a for loop right, how would that look like? just curious.
007Julien, good code. Basically I’m lost. lol. I have a headache.
I understand the code as the index of the numbers picked from the range are removed on each ball, then instead of say 1 through range  1  59, the next range for the next pick is 1  58? I am lost because I just want to pick for the same range regardless if same numbers are picked.
I did get something from your code though, it reminds me of how much I do not like ie, ie all versions.

I do not want to have all numbers randomly be the same, but the probability of that happening is slim to none if there a way to diminish this?

It is very simple !
For the first choice we choose randomly a rank between 159 and choose the corresponding number (for example 17).
Then we choose a rank between the remainder choices which are only 58 (for example 33).
The remaining numbers (color black):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 ... 59
There ranks:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 no 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ... 58
To take the 33rd remaining choice we have not to count 17, we progress after this value with a difference of 1. Then we take the number 34. And so on...
Last edited by 007Julien; 02082013 at 09:41 PM.

Let me say what you just said 007; the first iteration 17 is taken. Then instead of 159 when it randomly picked 17, 33 is picked with a range of 158. Each time a number it picked the range of numbers is decreased by 1.
That is not what I want to do. The range for the columns should never change. Yes as a result from that values could be the same and that it fine. In your idea 007 do you know if splicing the value chosen and then adding it back to the end of the values effect is differently? That seems like to much unnecessary work to me.
Like what you showed me:
The remaining numbers (color black):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 ... 59
There ranks:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ... 58.length + "17"(so 59 again/still)
I did solve what I ultimately wanted, thank you!

Sorry, I probably misspoke...
I just made random choices among the remaining numbers !
There is a good way of selecting several things out of a larger group without to renew unsuccessful choices, or to sort a large table (two actions that can become very long). In addition, it's not change the probability distribution.
I just wanted to treat your headaches...
Thread Information
Users Browsing this Thread
There are currently 1 users browsing this thread. (0 members and 1 guests)
Tags for this Thread
Posting Permissions
 You may not post new threads
 You may not post replies
 You may not post attachments
 You may not edit your posts

Forum Rules

