How do you randomize an array using actionscript 3?
There is a short version using Array.sort() function:
var arr : Array = [0,1,2,3,4,5,6,7,8,9];
function randomize ( a : *, b : * ) : int {
return ( Math.random() > .5 ) ? 1 : -1;
}
trace( arr.sort( randomize ) );
If you don't get "enough" randomness you can sort twice :)
EDIT - explanation line by line:
For Array class method sort() you can pass not only sort options like Array.CASEINSENSITIVE, Array.DESCENDING and so on but also your own custom compare function reference (a callback) that accepts two parameters (two elements from array to compare). From AS3 documentation:
A comparison function should take two arguments to compare. Given the elements A and B, the result of compareFunction can have a negative, 0, or positive value:
A negative return value specifies that A appears before B in the sorted sequence.
A return value of 0 specifies that A and B have the same sort order.
A positive return value specifies that A appears after B in the sorted sequence.
Note: compare function parameters might be typed (if your array is typed) and have any name you want eg.:
function compareElements ( elementA : SomeClass, elementB : SomeClass ) : int;
This method is very useful when you need to sort array elements by their special properties. In randomization case compareFunction randomly returns -1, 0 or 1 and makes array elements to switch their places (indices). I have found that better randomization (in my subjective and mathematically untested opinion) is when method returns only -1 and 1. Also have in mind that sorting function with custom compare function doesn't compare elements sequentially so in some special cases randomization results may differ from what you might expect.
There's a better way that will also allow you to randomize the array in place, if you need that, and it will not make you create more then a single copy of your original array.
package
{
import flash.display.Sprite;
public class RandomizeArrayExample extends Sprite
{
public function RandomizeArrayExample()
{
super();
testDistribution();
}
private function testDistribution():void
{
var hash:Object = { };
var tester:Array = [1, 2, 3, 4];
var key:String;
for (var i:int; i < 1e5; i++)
{
randomize(tester);
key = tester.join("");
if (key in hash) hash[key]++;
else hash[key] = 1;
}
for (var p:String in hash) trace(p, "=>", hash[p]);
}
private function randomize(array:Array):Array
{
var temp:Object;
var tempOffset:int;
for (var i:int = array.length - 1; i >= 0; i--)
{
tempOffset = Math.random() * i;
temp = array[i];
array[i] = array[tempOffset];
array[tempOffset] = temp;
}
return array;
}
}
}
I had an alternative requirement where i wanted to randomly insert lots of source arrays into a target array randomly. Like Rytis i'm a big fan of the forEach, map and sort functions on Arrays.
var randomInsert:Function = function callback(item:*, index:int, array:Vector.<MyItem>):void
{
var j:Number = Math.floor(Math.random() * targetArray.length);
targetArray.splice(j,0,item);
}
targetArray = new Vector.<MyItem>();
sourceArray1.forEach(randomInsert, this);
sourceArray2.forEach(randomInsert, this);
here's an easier function. Works also on multidimensional arrays
function randomizeArray(array:Array):Array
{
var newArray:Array = new Array();
while (array.length > 0)
{
var mn=Math.floor(Math.random()*array.length)
newArray[newArray.length]=array[mn]
array.splice(mn,1)
}
return newArray;
}
I found this very helpful. I hope it can help you too.
// Array to Randomize
var firstArray:Array = ["One","Two","Three","Four","Five","six","seven","eight","nine","ten"];
trace(firstArray); // Prints in order
var newArray:Array = new Array();
function randomizeArray(array:Array):Array
{
var newArray:Array = new Array();
while (array.length > 0)
{
newArray.push(array.splice(Math.floor(Math.random()*array.length), 1));
}
return newArray;
}
var randomArray:Array = randomizeArray(firstArray);
trace(randomArray); // Prints out randomized :)
If you need your array to be shuffled (your elements can not repeat). You could use this function:
/**
* Shuffles array into new array with no repeating elements. Simple swap algorithm is used.
*/
public function shuffleArray(original:Array):Array
{
// How many swaps we will do
// Increase this number for better results (more shuffled array, but slower performance)
const runs:int = original.length * 3;
var shuffled:Array = new Array(original.length);
var i:int;
var a:int;
var b:int;
var temp:Object;
// Copy original array to shuffled
for(i=0; i<shuffled.length; i++){
shuffled[i] = original[i];
}
// Run random swap cycle 'runs' times
for(i=0; i<runs; i++){
// There is a chance that array element will swap with itself,
// and there is always small probability it will make your shuffle
// results not that good, hence try to experiment with
// different runs count as stated above
a = Math.floor(Math.random() * original.length);
b = Math.floor(Math.random() * original.length);
// Swap messages
temp = shuffled[a];
shuffled[a] = shuffled[b];
shuffled[b] = temp;
}
return shuffled;
}
Usage:
var testArray:Array = ["Water", "Fire", "Air", "Earth"];
trace(shuffleArray(testArray).concat());
this is how I randomize my array of 36 cards for a memory game
const QUANT_CARTAS: int = 36;
//get the 36 numbers into the array
for (var i: int = 0; i < QUANT_CARTAS; i++)
{
cartas.push(i);
}
//shuffles them =)
for (var moeda: int = QUANT_CARTAS - 1; moeda > 0; moeda--)
{
var pos: int = Math.floor(Math.random() * moeda);
var carta: int = cartas[moeda];
cartas[moeda] = cartas[pos];
cartas[pos] = carta;
}
// and add them using the random order...
for (i = 0; i < QUANT_CARTAS; i++)
{
var novaCarta: Carta = new Carta();
novaCarta.tipoCarta = cartas[i];
etcetcetc.............
}
choose random string from array
function keyGenerator(len:Number):String
{
function randomRange(minNum:Number, maxNum:Number):Number
{
return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
}
var hexArray = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'];
var key = "";
for (var i=0; i<len; i++)
{
key += hexArray[randomRange(0,hexArray.length-1)];
}
return key;
}
usage:
trace(keyGenerator(16));
Related
I can't change elements of array using anonymous function:
var collection=[0, 1, 2];
collection.forEach((c)=> c+=1);
print(collection);
This variant doesn't work eithter:
var collection = [0, 1, 2];
for (var x in collection) {
x=x+1;
}
print(collection);
If you wish to replace/update all items in a list (List<int> items = [1, 2, 3]):
items = items.map((x) => x + 1).toList();
for (int i = 0; i < items.length; i++) items[i] += 1;
items = List<int>.generate(items.length, (i) => items[i] + 1);
List<int> tempItems = [];
items.forEach((x) => tempItems.add(x + 1));
items = tempItems;
You can't change the arguments to a function or var-in loop. You can call methods on them, which might have the side effect of mutating them, but assigning directly to them will not alter the value from which they are effectively copied.
collection.forEach((c)=> c+=1);
In above line you are incrementing parameter by 1 and that will not affect to the list.
It's equavalent to:
collection.forEach((int c) {// in this case int because list contains int's
c = c + 1;
});
As you can see, no point of changing the value of a parameter(local variable).
Since it's 0,1,2, you can do like this: collection.forEach((c)=> collection[c] = c+1);. That is stupid way because whenever you change any value, you will get an error(out of range).
So, here are some ways that you can change list values:
The easy way:
void main() {
var collection=[0, 1, 2];
for(int i = 0; i < collection.length; i++) {
collection[i] += 1;
}
print(collection);
}
Using replaceRange:
void main() {
var collection=[0, 1, 2];
var temp = collection.map((c) => c+1).toList();
collection.replaceRange(0, collection.length, temp);
print(collection);
}
The array:
var numberArray:Array= new Array(34,53,2,3,34,26,26,85,3,4,98,2,12);
How do I trace it so the output-panel will show every other item: "34,2,34,26,3,98,12"
How do I trace the numbers that have a lower value than 10
How do I trace the even numbers in the array?
For the reference and general education: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Vector.html#map()
// You can init Arrays with [] operator.
var numberArray:Array = [34,53,2,3,34,26,26,85,3,4,98,2,12];
trace(filter(numberArray, evenIndices));
trace(filter(numberArray, belowTen));
trace(filter(numberArray, evenValues));
// In AS3 you can pass method references as function arguments.
// That allows to compose a filtering method, just like Vector.map(...)
// This method will filter the original array
// by the given criteria and return the filtered result.
// Criteria method must accept 2 arguments: element index and value.
function filter(source:Array, criteria:Function):Array
{
var result:Array = new Array;
for (var i:int = 0; i < source.length; i++)
if (criteria(i, source[i]))
result.push(source[i]);
return result;
}
// Returns true if index is an even number.
function evenIndices(index:int, value:int):Boolean
{
return index % 2 == 0;
}
// Returns true if value is less than 10.
function belowTen(index:int, value:int):Boolean
{
return value < 10;
}
// Returns true if value is an even number.
function evenValues(index:int, value:int):Boolean
{
return value % 2 == 0;
}
var numberArray:Array = [34, 53, 2, 3, 34, 26, 26, 85];
1.How do I trace it so the output-panel will show every-other item: "34,2,34,26,3,98,12"
getEventIndexiesOfArray(numberArray);
2.How do I trace the numbers that have a lower value than 10
lenghtLessthanTen(numberArray);
3.How do I trace the even numbers in the array?
checkArrayHasEventLenght(numberArray);
1. getEventIndexiesOfArray() method for get event indexies elements from array.
private function getEventIndexiesOfArray(source:Array):void
{
var resultArr:Array = [];
for (var i:int = 0; i < source.length; i++)
{
if (i % 2 == 0)
resultArr.push(source[i]);
}
trace("Even Indexies Array : " + resultArr.toString());
}
2. lenghtLessthanTen() method for check that array lenght is lessthan 10 or not.
private function lenghtLessthanTen(source:Array):void
{
if (source.length < 10)
trace("Array containt lessthan Ten elements");
}
3. checkArrayHasEventLenght() method check that array containt even lenght or not.
private function checkArrayHasEventLenght(source:Array):void
{
if (source.length % 2 == 0)
trace("Array has even number of elenter code hereements");
}
I'm looking for the fastest way to pick a random object that has a certain condition (from an array).
In the example below I have a multidimensional array, 50 * 50 that contains objects. I want to pick a random object from that array but that object needs to have a size larger than 100.
while (object.size <= 100)
{
attempts++;
object = grid_array[Math.round(Math.random() * 49)][Math.round(Math.random() * 49)];
}
Currently I have tested this and in some instances it takes over 300+ attempts. Is there a more elegant way to do this?
Thanks,
What I would do is first filter the source array to extract only valid candidates, then return a random one (if there are any).
For example:
function getRandomObject(grid_array:Array, minSize:Number):Object {
var filtered:Array = [];
for(var i:int = 0; i < grid_array.length; i++){
var inner:Array = grid_array[i];
for(var ii:int = 0; ii < inner.length; ii++){
var object:Object = inner[ii];
if(object.size >= minSize){
filtered.push(object);
}
}
}
return filtered.length ? filtered[int(Math.random() * filtered.length)] : null;
}
// example:
var object:Object = getRandomObject(grid_array, 100);
if(object){
// do stuff with `object`
}
I asked if you need the indexes because you could do this with RegExps and the JSON Class (Flash Player 11). With this example I stored the indexes of the objects:
Create random multidimensional Array to test the function
//---I stored a variable size and the indexes inside the Object
//---Size variable will be numbers between 0 and 500
var array:Array = [];
var i;
var j;
var size:uint = 50;
var obj:Object;
for(i = 0; i < size; i++){
array[i] = [];
for(j = 0; j < size; j++){
obj = new Object();
obj.size = Math.floor(Math.random() * 500);
obj.files = i;
obj.columns = j;
array[i][j] = obj;
}
}
Method to get random Object with size property bigger than 100
//---I'll use to search the object a JSON string
var str:String = JSON.stringify(array);
//---Function to get the random Object
function getRandom():Object{
//---RegExp to search object with size between 100 and 500
var reg:RegExp = /\{[^\}]*"size":(?:10[1-9]|1[1-9]\d|[2-5]\d\d)[^\}]*\}/g;
//---Get all matches
var matches:Array = str.match(reg);
//---Return a random match converted to object
//---If no match founded the return will be null
return matches ? JSON.parse( matches[Math.floor(Math.random() * matches.length)] ) : null;
}
I have an array of skin tone hex codes. At the moment, when I click a button, it randomly gets an element from the array. I'd like it to just get the next available element and if there are no more, loop back to the 1st element. Here's what I have at the moment.
var skinTones:Array = ["0xebae7f","0x754c24","0xf2ca8d","0xf4d1b7","0x8b6947"];
And the button code:
menuMC.buttFace.addEventListener(MouseEvent.CLICK, clickFace);
function clickFace(event:MouseEvent): void
{
function getSkinTone(source, amount) {
var i = Math.round(Math.random() * (source.length - 1)); //random seed (starting point)
var myTone = new Array(); //the new array
while(myTone.length < amount){
if (i >= source.length) i = 0; //if the current iterator if out of bounds, reset to 0
myTone.push(source[i]);
i++;
}
return myTone;
}
var toneHex = getSkinTone(skinTones,1);
trace(toneHex);
TweenLite.to(faceWrapperMC.faceMC, 0.5, {colorTransform:{tint:toneHex, tintAmount:1}});
TweenLite.to(faceWrapperMC.earsMC, 0.5, {colorTransform:{tint:toneHex, tintAmount:1}});
TweenLite.to(faceWrapperMC.eyesMC.eyes.eyelid, 0.5, {colorTransform:{tint:toneHex, tintAmount:1}});
}
Any help would be great. Also, if it can be simplified, please let me know. This is my 1st AS3 project.
This will take the passed array, and return a new array with a random seed (starting element) and keep the rest of the order the same. I renamed the parameters to better clarify what I interpreted them to be.
function getSkinTone(source:Array,amount:int):Array {
var i:int = Math.round(Math.random() * (source.length - 1)); //random seed (starting point)
var myTone:Array = new Array(); //the new array
while(myTone.length < amount){
if (i >= source.length) i = 0; //if the current iterator if out of bounds, reset to 0
myTone.push(source[i]);
i++;
}
return myTone;
}
EDIT
After some comments, I believe this is what you'd like to do:
var skinTones:Array = ["0xebae7f","0x754c24","0xf2ca8d","0xf4d1b7","0x8b6947"]; //these can be stored as uint instead of strings since TweenLite will just convert them to uint anyway
var skinToneIndex:int = -1; //a global var to hold the current index - starting as -1 to indicate it hasn't been set yet.
function getNextSkinTone():String {
if(skinToneIndex == -1) skinToneIndex = Math.round(Math.random() * (skinTones.length - 1)); //if not set, make it a random starting number
skinToneIndex++; //increment it
if(skinToneIndex >= skinTones.length) skinToneIndex = 0; //if out of bounds reset to 0;
return skinTones[skinToneIndex];
}
menuMC.buttFace.addEventListener(MouseEvent.CLICK, clickFace);
function clickFace(event:MouseEvent): void {
var toneHex:uint = getNextSkinTone();
trace(toneHex);
TweenLite.to(faceWrapperMC.faceMC, 0.5, {colorTransform:{tint:toneHex, tintAmount:1}});
TweenLite.to(faceWrapperMC.earsMC, 0.5, {colorTransform:{tint:toneHex, tintAmount:1}});
TweenLite.to(faceWrapperMC.eyesMC.eyes.eyelid, 0.5, {colorTransform:{tint:toneHex, tintAmount:1}});
}
This might be a simple one, and if it is I'm sure I'll feel stupid.
Basically, I have arrays a1, a2 and a3.
Using a for statement..
for (var i 0; i < 4; i++) {
//stuff
}
How can I push data in the for statement into one of these arrays using i? That is, each time adding the data into the next group up. a[0] -> a[1] etc. I tried getDefinitionByName but it seems that only works for library objects!
Sorry if it's simple!
Cheers in advance.
EDIT:
The code in full where I need this to work. This is what I tried using the first answer I was given.
var fullList:Vector.<Array> = new Vector.<Array>();
for (var i1 = 0; i1 < 3; i1++)
{
fullList.push(new Array());
}
var levelLoader:URLLoader = new URLLoader();
levelLoader.addEventListener(Event.COMPLETE, levelLoaded);
function levelLoaded(e:Event):void
{
var indexcount = 0;
txttileArray = e.target.data.split("a");
txtDebug.text = txttileArray.toString();
for (var i = 1; i < 4; i++)
{
temparray1 = txttileArray[indexcount].split("");
for (var row = 0; row < temparray1.length; row ++)
{
var a = getDefinitionByName(temparray1[row] + "Tile") as Class;
//trace(a);
var b = new a ;
b.x = 17 + 17 * row;
b.y = 17 + 17 * indexcount;
addChild(b);
fullList[indexcount].push(b);
}
indexcount++;
}
}
sorry for the messy variable names.
i have three arrays, a1, a2 and a3. i want to be able access these
arrays based on the value of the variable "i". so for example, if "i"
is 1, i want to push a data value to a1. and so on – hazdog
This is not possible if you have arrays a1, a2 and a3 as local (defined in the function) variables. If they are defined in the class, then here's how you do it:
private var a1:Array=[];
private var a2:Array=[];
private var a3:Array=[];
private function pushValue(identifier:String, value:Object):int {
var name:String="a" + identifier;
var target:Array=this[name] as Array;
if(target == null) {
throw new Error("No such array " + name);
} else {
return target.push(value);
}
}
//And then call it like this:
pushValue("1", "This value goes in array a1");
pushValue("1", "This is another value that goes in array a1");
pushValue("2", "This value goes in array a1");
pushValue("2", "This is another value that goes in array a2");
pushValue("3", "This value goes in array a3");
pushValue("3", "This is another value that goes in array a3");
Otherwise, you can define an array of arrays (or vector of arrays), say holderArray in which you put your target arrays, and then push the value to holderArray[identifier]
EDIT
Instead of defining a1, a2 and a3 in the this object, define it like this:
private var arrayHolder:Object={};
private function init():void {
for(var i:int=1; i<=3; i++) {
arrayHolder["a" + i]=new Array();
}
}
init();
Then, your arrays will be stored as arrayHolder.a1, arrayHolder.a2, arrayHolder.a3 etc
And modify pushValue as follows:
Change
var target:Array=this[name] as Array;
to
var target:Array=arrayHolder[name] as Array;
Inception.
You need to use Array in Array.
private var fullList:Vector.<Array>;
private var total:uint = 4;
function a():void
{
// first creating array list
fullList = new Vector.<Array>();
for (var i:uint = 0; i < total; i++)
{
fullList.push(new Array());
}
}
function b():void
{
// doing the stuff
for (var i:uint = 0; i < total; i++)
{
switch (i)
{
case 0:
fullList[i].push('zero-array-push');
break;
case 1:
fullList[i].push('one-array-push');
break;
case 2:
fullList[i].push('two-array-push');
break;
case 3:
fullList[i].push('three-array-push');
break;
}
}
}