Mond
269 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
119 posts
|
Array.push(num) returns the new length of the array.
|
|
|
Mond
269 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
126 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
119 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
269 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
1704 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
223 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
1704 posts
|
I kept the ( and ) for clarification. When Flash Player runs the code, the () won’t be there.
|
|
|
SuperMarioJump
223 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
1704 posts
|
Ya, I believe the [0] was a typo that the thread owner accidentally put in.
|
|
|
the8bitYoda
58 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
1704 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
223 posts
|
I just tried it in FlashDevelop and it compiles fine.
|
|
|
the8bitYoda
58 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
2343 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
1704 posts
|
Ah, but its still works, as stated by the8bitYoda in the post above.
|
|
|
Draco18s
2343 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
223 posts
|
You don’t have to convert it to an interger, it’s done so implicitly.
|
|
|
Draco18s
2343 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
269 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
223 posts
|
|
|
|
Mond
269 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
223 posts
|
I’m not sure what the point you’re making here is.
|
|
|
Mond
269 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
|