Mond
699 posts
|
var chosen:Array = new Array();
for (var i:int = 0; i < 25; i++) trace(i, EquallyWeighted_NonRepeatingRandom(20, chosen));
function EquallyWeighted_NonRepeatingRandom(arrayLength:uint, chosen:Array):int
{
var theNum:int = 0;
if (chosen.length == arrayLength) return -1;
if (!arrayLength) return -1;
do
{
theNum = Math.round(Math.random() * (arrayLength + 2));
}
while ((theNum == 0) || (theNum == arrayLength + 2) || (chosen.indexOf(theNum - 1) != -1));
return chosen.push(--theNum);
} //end of function EquallyWeighted_NonRepeatingRandom
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16
16 17
17 18
18 19
19 20
20 -1
21 -1
22 -1
23 -1
24 -1
This algorithm should be choosing randomly & not repeating any choices, but the output is in order and I don’t know why. Does anybody see where my code is incorrect?
EDIT: I added this line of code for debug:
for (i = 0; i < chosen.length; i++) trace("chosen[" + i + "]:" + chosen[i]);
chosen[0]:8
chosen[1]:13
chosen[2]:14
chosen[3]:19
chosen[4]:15
chosen[5]:17
chosen[6]:18
chosen[7]:16
chosen[8]:2
chosen[9]:7
chosen[10]:1
chosen[11]:3
chosen[12]:0
chosen[13]:4
chosen[14]:20
chosen[15]:11
chosen[16]:12
chosen[17]:6
chosen[18]:5
chosen[19]:10
The elements in the chosen array are random! WTH…..I return the return from the push!?
EDIT2: I found it, the push returns the length of the chosen array, I thought it returned whatever was pushed.
|
|
|
Wordblind
1053 posts
|
Array.push(num) returns the new length of the array.
|
|
|
Mond
699 posts
|
Here is the corrected code with its corresponding output:
var chosen:Array = new Array();
for (var i:int = 0; i < 25; i++) trace(i, EquallyWeighted_NonRepeatingRandom(20, chosen));
trace();
for (i = 0; i < chosen.length; i++) trace("chosen[" + i + "]:" + chosen[i]);
function EquallyWeighted_NonRepeatingRandom(arrayLength:uint, chosen:Array):int
{
var theNum:int = 0;
if (chosen.length == arrayLength + 1) return -1;
if (!arrayLength) return -1;
do
{
theNum = Math.round(Math.random() * (arrayLength + 2));
}
while ((theNum == 0) || (theNum == arrayLength + 2) || (chosen.indexOf(--theNum) != -1));
chosen.push(theNum);
return theNum;
} //end of function EquallyWeighted_NonRepeatingRandom
0 5
1 2
2 1
3 14
4 3
5 11
6 18
7 20
8 15
9 8
10 0
11 13
12 7
13 17
14 9
15 12
16 16
17 6
18 4
19 10
20 19
21 -1
22 -1
23 -1
24 -1
chosen[0]:5
chosen[1]:2
chosen[2]:1
chosen[3]:14
chosen[4]:3
chosen[5]:11
chosen[6]:18
chosen[7]:20
chosen[8]:15
chosen[9]:8
chosen[10]:0
chosen[11]:13
chosen[12]:7
chosen[13]:17
chosen[14]:9
chosen[15]:12
chosen[16]:16
chosen[17]:6
chosen[18]:4
chosen[19]:10
chosen[20]:19
I realize this code could become “jammed up” in the do..while statement. Does anyone have a better way of doing this?
|
|
|
CuriousGaming
392 posts
|
What do you want to happen after all 20 numbers have come out? Repeat the sequence? A default number, like -1?
An alternative method is to put sequential numbers into an array, and mix them all up:
(repeat 50 times)
- swap (random array element with another random array element)
Then use array.pop until the array is empty.
|
|
|
Wordblind
1053 posts
|
The standard method is similar, except only one side of the swap is random.
function shuffle(cards:Array) {
var temp:*, rand:uint, index:uint, length:uint = cards.length;
for(index in cards) {
rand = Math.floor(Math.rand() * length);
temp = cards[index];
cards[index] = cards[rand];
cards[rand] = temp;
}
}
|
|
|
Mond
699 posts
|
Thanks ya’ll. Math.floor, which I have never looked at before, avoids the unequal weighting of Math.round. It cuts much fat off my original idea. Almost a one-liner:
var chooseFrom:Array = new Array();
for (var i:int = 0; i < 15; i++) chooseFrom.push(i);
for (i = 0; i < 20; i++) trace(i, NonRepeatingRandom(chooseFrom));
function NonRepeatingRandom(chooseFrom:Array):int
{
if (!chooseFrom.length) return -1;
return chooseFrom.splice(Math.floor(Math.random() * chooseFrom.length), 1)[0];
} //end of function NonRepeatingRandom
0 6
1 13
2 10
3 3
4 1
5 2
6 11
7 14
8 5
9 4
10 12
11 9
12 7
13 8
14 0
15 -1
16 -1
17 -1
18 -1
19 -1
|
|
|
UnknownGuardian
6208 posts
|
Of you could have just cast the number to an int. If would look like this
function NonRepeatingRandom(chooseFrom:Array):int
{
if (!chooseFrom.length) return -1;
return chooseFrom.splice((int)(Math.random() * chooseFrom.length), 1)[0];
} //end of function NonRepeatingRandom
Where (int) replaced Math.floor You also might check on efficiency if its a big deal.
|
|
|
SuperMarioJump
303 posts
|
function NonRepeatingRandom(chooseFrom:Array):int
{
if (!chooseFrom.length) return -1;
return chooseFrom.splice(int(Math.random() * chooseFrom.length), 1)[0];
} //end of function NonRepeatingRandom
I don’t think you need the [0] on the end either
|
|
|
UnknownGuardian
6208 posts
|
I kept the ( and ) for clarification. When Flash Player runs the code, the () won’t be there.
|
|
|
SuperMarioJump
303 posts
|
I thought you’d been playing with C and gotten confused. I still don’t think you need the [0] at the end of splice.
|
|
|
UnknownGuardian
6208 posts
|
Ya, I believe the [0] was a typo that the thread owner accidentally put in.
|
|
|
the8bitYoda
79 posts
|
Originally posted by UnknownGuardian:
Ya, I believe the [0] was a typo that the thread owner accidentally put in.
The splice() method returns an array, since the function expects an int to be returned the [ 0] is necessary.
|
|
|
UnknownGuardian
6208 posts
|
Originally posted by the8bitYoda:
Originally posted by UnknownGuardian:
Ya, I believe the [0] was a typo that the thread owner accidentally put in.
The splice() method returns an array, since the function expects an int to be returned the [ 0] is necessary.
Ya, but isn’t the goal of the method to return a value? Doesn’t splice just return a value if you just get 1 index?
|
|
|
SuperMarioJump
303 posts
|
I just tried it in FlashDevelop and it compiles fine.
|
|
|
the8bitYoda
79 posts
|
I stand corrected, it does compile fine, so it is optional to have the [ 0] (but not wrong) in this case. The compiler apparently let’s you implicitly cast the returned Array to an int. splice() always returns an Array, which can be verified by:
//Assuming arr is an Array of integers
trace((arr.splice(1,1)) is Array); //true
trace((arr.splice(1,1)) is int); //false
trace((arr.splice(1,1))[ 0] is Array); //false
trace((arr.splice(1,1))[ 0] is int); //true
trace(int(arr)); //Returns the integer if arr has only one element, returns 0 otherwise.
Strange behavior I think…but interesting to know.
|
|
|
Draco18s
5875 posts
|
Originally posted by UnknownGuardian:
Originally posted by the8bitYoda:
Originally posted by UnknownGuardian:
Ya, I believe the [0] was a typo that the thread owner accidentally put in.
The splice() method returns an array, since the function expects an int to be returned the [ 0] is necessary.
Ya, but isn’t the goal of the method to return a value? Doesn’t splice just return a value if you just get 1 index?
No, it returns an array length 1 with a single value at index 0.
|
|
|
UnknownGuardian
6208 posts
|
Ah, but its still works, as stated by the8bitYoda in the post above.
|
|
|
Draco18s
5875 posts
|
Originally posted by UnknownGuardian:
Ah, but its still works, as stated by the8bitYoda in the post above.
If you convert it to an integer, then yes, it works, that’s what the int() function does, and one of the really neat things about figuring out what the integer value of something is is you can go “oh, that’s a 1 element array, I’ll return the integer value of the 0th index” because its the only integer that could represent that array meaningfully.
|
|
|
SuperMarioJump
303 posts
|
You don’t have to convert it to an interger, it’s done so implicitly.
|
|
|
Draco18s
5875 posts
|
Originally posted by SuperMarioJump:
You don’t have to convert it to an interger, it’s done so implicitly.
Type inference, or implicit typing, refers to the ability to deduce automatically the type of a value in a programming language.
Ta da, just because its converted implicitly doesn’t mean its not an array.
|
|
|
Mond
699 posts
|
Maybe explicitly..because of the function’s return typing..so I tried it with Number:
var myNumber:Number = 1.0;
trace(myNumber);
var chooseFrom:Array = new Array();
for (var i:int = 14; i >= 0; i--) chooseFrom.push(i);
for (i = 0; i < 20; i++) trace(i, NonRepeatingRandom(chooseFrom));
function NonRepeatingRandom(chooseFrom:Array):Number
{
if (!chooseFrom.length) return -1;
return chooseFrom.splice(Math.floor(Math.random() * chooseFrom.length), 1); //[0];
} //end of function NonRepeatingRandom
1
0 4
1 14
2 10
3 8
4 9
5 0
6 2
7 13
8 6
9 11
10 3
11 7
12 5
13 1
14 12
15 -1
16 -1
17 -1
18 -1
19 -1
But the trace call drops the decimal part.
|
|
|
SuperMarioJump
303 posts
|
|
|
|
Mond
699 posts
|
1.0
0 4.0
1 14.0
2 10.0
3 8.0
4 9.0
5 0.0
6 2.0
7 13.0
8 6.0
9 11.0
10 3.0
11 7.0
12 5.0
13 1.0
14 12.0
15 -1.0
16 -1.0
17 -1.0
18 -1.0
19 -1.0
|
|
|
SuperMarioJump
303 posts
|
I’m not sure what the point you’re making here is.
|
|
|
Mond
699 posts
|
var myNumber:Number = 1.0;
trace(myNumber, myNumber is Number);
var chooseFrom:Array = new Array();
for (var i:int = 5; i >= 0; i--) chooseFrom.push(i);
for (i = 0; i < 7; i++)
{
myNumber = NonRepeatingRandom(chooseFrom);
trace(i, myNumber, myNumber is Number);
}
function NonRepeatingRandom(chooseFrom:Array):Number
{
if (!chooseFrom.length) return -1;
return chooseFrom.splice(int(Math.random() * chooseFrom.length), 1); //[0];
} //end of function NonRepeatingRandom
1 true
0 4 true
1 3 true
2 1 true
3 5 true
4 2 true
5 0 true
6 -1 true
|