As3 - Script Error on Arrays - actionscript-3

please inspect me coding:
function createRandomList():void
{
var newlist:Array = [0,1,2];
var curlist:Array = item[selectedlevel - 1] //selectedlevel = 1;
var normal:int = curlist[0];
var tempboo1:Boolean = false;
var tempboo2:Boolean = false;
var tempboo3:Boolean = false;
while (curlist[0] + curlist[1] + curlist[2] > 0)
{
if (Number(curlist[0]) == 0 && tempboo1 == false)
{
newlist.splice(newlist.indexOf(0), 1);
tempboo1 = true;
}
if (Number(curlist[1]) == 0 && tempboo2 == false)
{
newlist.splice(newlist.indexOf(1), 1);
tempboo2 = true;
}
if (Number(curlist[2]) == 0 && tempboo3 == false)
{
newlist.splice(newlist.indexOf(2), 1);
tempboo3 = true;
}
var temp:int = Math.floor(Math.random()*(newlist.length));
curlist[temp] -= 1;
generatedlist.push(Number(newlist[temp]));
trace(item);
}
while (normal > 0)
{
var temp2:int = Math.floor(Math.random() * 3) + 1;
generatednormal.push(Number(temp2));
normal--;
}
}
My item was [[5,0,0],[10,0,0]];
But after became [[0,0,0],[0,0,0]];
I just want to duplicate Array item to be a new variable curlist.
Every time it traces, returning item[0][0] decreasing 1, I only want to use curlist as a temp Array to calculate a new random Array based on item[0].
Ouput:
4,0,0,10,0,0
3,0,0,10,0,0
2,0,0,10,0,0
1,0,0,10,0,0
0,0,0,10,0,0
Is there any links between them, or is it my problem? Please help! If you need any more infoemation, please comment me!

Arrays are passed by reference, not value. That means when you modify an array through any property that points to it, the original array will be modified.
To make a duplicate, you can use .slice()
Returns a new array that consists of a range of elements from the original array, without modifying the original array. The returned array includes the startIndex element and all elements up to, but not including, the endIndex element.
If you don't pass any parameters, the new array is a duplicate (shallow clone) of the original array.

You can clone your arrays if you want to create a new reference.
function clone( source:Object ):*
{
var myBA:ByteArray = new ByteArray();
myBA.writeObject( source );
myBA.position = 0;
return( myBA.readObject() );
}
var a:Array = [[0,0],[1,1]];
var b:Array = clone(a);
b[0] = [2,2];
trace(a)
trace(b)
Output
0,0,1,1
2,2,1,1
It works for any object, not only arrays.
More infos here : AS3 - Clone an object

var array : Array = [ 1, 2, 3];
var array2 : Array = array.concnt();
array[ 0 ] = 4;
trace( array );// 1, 2, 3
trace( array 2);// 4, 2 ,3
So use .concat() to duplicate an array with primitives. If you have an arrays with arrays. Duplicate the children arrays, and put them into an empty one. If you have children of children arrays and so forth, make something recursive.

Related

How to add numbers in array via a loop in AS3?

var arr: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9];
I can add these numbers to an array separately like this but how do I add 1 to 50 at once instead of typing it all the way through?
for (var i:Number=1; i<=50;i++){
var arr:Array(i) = [i];
}
function randomize(a: * , b: * ): int {
return (Math.random() > .5) ? 1 : -1;
}
trace(arr.sort(randomize));
I am trying to implement something like this.
Thank you.
Pretty simple. You can address the Array's elements via square bracket notation. Works both ways:
// Assign 1 to 10-th element of Array A.
A[10] = 1;
// Output the 10-th element of A.
trace(A[10]);
Furthermore, you don't even need to allocate elements in advance, Flash Player will automatically adjust the length of the Array:
// Declare the Array variable.
var A:Array;
// Initialize the Array. You cannot work with Array before you initialize it.
A = new Array;
// Assign some random elements.
A[0] = 1;
A[3] = 2;
// This will create the following A = [1, null, null, 2]
So, your script is about right:
// Initialize the Array.
var arr:Array = new Array;
// Iterate from 1 to 50.
for (var i:int = 1; i <= 50; i++)
{
// Assign i as a value to the i-th element.
arr[i] = i;
}
Just keep in mind that Arrays are 0-based, so if you forget about index 0 it will remain unset (it will be null).

Array of column Letters to Array of Column Numbers not working

This is more or less my first attempt at writing a Javascript function and I want to convert an array of column numbers to an array of column letters
If I run testFunction I get undefined
function testFunction() {
var ui = SpreadsheetApp.getUi();
aryCLTCN(["A","C","D"])
ui.alert(aryCLTCN[3]);
}
function aryCLTCN(array) {
var columnLet = array
var output = [];
for (var i = 0, length = columnLet.length; i < length; i++) {
output[i] = [];
output[i] = CLTCN(columnLet[(i)]);
}
}
function CLTCN(letter)
{
var column = 0, length = letter.length;
for (var i = 0; i < length; i++)
{
column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
}
return column;
}
There are several problems with your code.
Within function testFunction() you call aryCLTCN(["A","C","D"]) but don't assign the result to a variable, then with aryCLTCN[3] you are trying to access a property "3" of the function itself. Which isn't a syntax error because functions can have properties, but the function has no such property so you get undefined. You need something like this:
var result = aryCLTCN(["A","C","D"]);
ui.alert(result[3]);
Except note that JavaScript arrays are zero-based, which means that [3] tries to access the fourth element, but your array only has three elements.
Within function aryCLTCN(array) you create an output array but don't return it. You need to add return output;.
Also with these two lines:
output[i] = [];
output[i] = CLTCN(columnLet[(i)]);
...the first line assigns output[i] to a new empty array, but the second line overwrites that with the return value from CLTCN(columnLet[(i)]);. You can remove output[i] = [];.
Putting all that together:
function testFunction() {
// var ui = SpreadsheetApp.getUi(); // commented out for demo in browser
var result = aryCLTCN(["A","C","D"])
// using alert() instead of ui.alert() for demo here in browser
alert(result[3]); // undefined because there's no 4th element
alert(result[2]); // shows third element
}
function aryCLTCN(array) {
var columnLet = array
var output = [];
for (var i = 0, length = columnLet.length; i < length; i++) {
output[i] = CLTCN(columnLet[(i)]);
}
return output;
}
function CLTCN(letter)
{
var column = 0, length = letter.length;
for (var i = 0; i < length; i++)
{
column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
}
return column;
}
testFunction();
(Note that for the purposes of having a runnable code snippet in my answer I'm using alert() instead of ui.alert(), but in your real code you would stick with ui.alert().)
You get an undefined error because you are calling the trying to access an index on a function. aryCLTCN function needs to have a return the output array and you need to assign it to a variable in your testFunction to be able to access its elements.
Although there was nothing logically or effectively wrong with your functions, I have provided another working solution below.
function testFunction() {
var ui = SpreadsheetApp.getUi();
var colArr = ["A", "B", "Z", "AA", "AZ", "ZA", "AAA"];
var nColArr = colArr.map(function(col) {
var colNum = 0;
col.split('').forEach(function(l, i) { colNum += (l.charCodeAt() - 64) * Math.pow(26, col.length - 1 - i) });
return colNum;
});
ui.alert(nColArr); //Shows all elements inside the nColArr array.
ui.alert(nColArr[3]); //Shows the 4th element inside the nColArr array.
}
Try it out:
var colArr = ["A", "B", "Z", "AA", "AZ", "ZA", "AAA"];
var nColArr = colArr.map(function(col) {
var colNum = 0;
col.split('').forEach(function(l, i) {
colNum += (l.charCodeAt() - 64) * Math.pow(26, col.length - 1 - i)
});
return colNum;
});
console.log(nColArr);

Simplest way to prevent math.random form selecting the same number twice (AS3)

I have a random number variable defined as below
var rannum:Number = Math.floor(Math.random()*50+1);
Then I have a trigger that calls for a new random number everytime a button is clicked
ranbtn.addEventListener(MouseEvent.CLICK, reran);
function reran (event:MouseEvent):void
{
rannum = Math.floor(Math.random()*50+1);
}
I would like to prevent the same random number from being selected until all the numbers have been selected and then possibly start over?
I found a few threads like this one but none of them were specifically what I needed
You need to create an array of the possible values and each time you retrieve a random index from the array to use one of the values, you remove it from the array.Here you have an easy example with javascript.
var uniqueRandoms = [];
var numRandoms = 50;
function makeUniqueRandom() {
// refill the array if needed
if (!uniqueRandoms.length) {
for (var i = 0; i < numRandoms; i++) {
uniqueRandoms.push(i);
}
}
var index = Math.floor(Math.random() * uniqueRandoms.length);
var val = uniqueRandoms[index];
// now remove that value from the array
uniqueRandoms.splice(index, 1);
return val;
}
I've found another option, You can declare an array of Integers:[1,2,3,4...50] and sort them randomly.
var sorted:Array = [];
for(var i:int = 0; i < 50; i++){
sorted.push(i);
}
//I'm making a copy of sorted in unsorted
var unsorted:Array = sorted.slice();
//Randomly sort
while(sorted.join() == unsorted.join()){
unsorted.sort(function (a:int, b:int):int { return Math.random() > .5 ? -1 : 1; });
}
If you get a selected num, you can add one until it is not selected.
Create a list of integers from 1 to 50.
Pick a random integer from the list and remove it.
When there are no more integers left (after 50 picks), repeat step 1.
Code:
function createRangeOfIntegers(from:int, to:int):Vector.<int> {
if (from >= to) throw new ArgumentError("Invalid arguments");
var integers:Vector.<int> = new <int>[];
for (var i:int = from; i <= to; i++) {
integers.push(i);
}
return integers;
}
function getRandomInteger(integers:Vector.<int>):int {
var index:int = Math.random() * integers.length;
var integer:int = integers.splice(index, 1)[0];
return integer;
}
Example:
// create all the possible integers
var integers:Vector.<int> = createRangeOfIntegers(1, 50);
// select a random integer
var random:int = getRandomInteger(integers);
// When you've selected all integers you can start over
if (integers.length == 0)
integers = createRangeOfIntegers(1, 50);

Sorting a multidimentional array and moving all the same values to the last array in as3

I'm currently working on a primitive graphic for the inventory
that shows how much space is currently taken and how much theres
left.
It does this by showing 5 rows of 20 squares
(Gray = free space, yellow =space taken).
Now, my problem is that I want to find all values that
are 1 and put them in the last array.
So that the array goes from:
var myMap:Array = [
[1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0],
[1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0],
[1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0],
[1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],
[1,0,0,0,0,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0]
];
to
var myMap:Array = [
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
];
Basically I want to sort the entire array so that all zero's come first
and all 1's get put in the last one till its full, then the second last one and so on.
I'm away I will most likely need an algorithm for this but I am hoping theres an easier way to do this. I'm usually a C# developer so AS3 is not my strongest suit.
hopefully someone understood what I ment and can help me, its 4:30 am, so I might not be as lucid as I'd like.
~Thanks
EDIT
Added the code so people can get more of a informed look:
Keep in mind most of the names and so on are placeholders, currently I just need it working.
private function _showInventoryGraphic()
{
var mapWidth = 20;
var mapHeight = 5;
var myMap:Array = [
[1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0],
[1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0],
[1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0],
[1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],
[1,0,0,0,0,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0]
];
var posX:int = 15;
var posY:int = 15;
var startPosY:int = 250;
for (var i:int=0; i<mapHeight; i++)
{
for (var u:int = 0; u < mapWidth; u++)
{
if (myMap[i][u] == 0)
{
var grayRect:Shape = new Shape;
grayRect.graphics.beginFill(0x808080);
grayRect.graphics.drawRect(posX*u, startPosY, 10,10);
grayRect.graphics.endFill();
addChild(grayRect);
}
if (myMap[i][u] == 1)
{
var yellowRect:Shape = new Shape;
yellowRect.graphics.beginFill(0xFFFF00);
yellowRect.graphics.drawRect(posX*u, startPosY, 10,10);
yellowRect.graphics.endFill();
addChild(yellowRect);
}
}
startPosY += posY;
}
}
After trying it out from a few different approaches, I think the biggest challenge is the fact that it is a 2d array.
The first attempt was similar, but like quicksort, where there were 2 pointers at either end of the 2d array and they moved 'inwards' looking for a scenario where the first pointer was a '1' and the last pointer was a '0' and swapping the two, until the pointers met in the 'middle'. I gave up on this method while trying to properly decrement and increment the linear counters in a 2d array. =b
The second attempt was by keeping track of the last index in the array that was as empty and the last index in the array that was full. Then within the addItem and removeItem methods I'd put the item in the correct spot and update the counters to avoid a sort. This seemed to work, but maybe a bit messy and perhaps harder to maintain in the future. It sorts the result in separate arrays.
In the third attempt for a 'direct sort', I think the most simple way then is just flatten the array apart in to a 2d array, sort it, then rejoin it. You would be correct in that this is not the most efficient method, though one thing to consider is how often this needs to run and how efficient it really needs to be given the context. I think a 2d array of only 100 elements is not too big of an issue to use an inefficient sort method?
Maybe someone else can come up with better/cleaner methods. =b
Below is code for what I mentioned.
Second attempt (Note: I did not test this one fully, but it seemed to work):
import flash.geom.Point;
var unsortedMap:Array = [
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0]
];
var sortedMap:Array = [
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0]
];
var rowSize:int = unsortedMap[0].length;
var rowCount:int = unsortedMap.length;
// points to the last index at start, since want to have filled items at the 'end'
var emptySpotPointer:Point = new Point(rowSize - 1, rowCount - 1);
var fullSpotPointer:Point = new Point(rowSize - 1, rowCount - 1);
function print2dArray(prefix:String, input:Array):void {
trace(prefix);
for(var row:String in input){
trace("\t"+ input[row]);
}
trace("");
}
function addItem(inputX:int, inputY:int):void {
if(unsortedMap[inputY][inputX] == 1){
trace("addItem() - Already an item here: "+ inputX +", "+ inputY);
return;
}
trace("addItem() - Adding an item: "+ inputX +", "+ inputY);
unsortedMap[inputY][inputX] = 1;
sortedMap[emptySpotPointer.y][emptySpotPointer.x] = 1;
fullSpotPointer.x = emptySpotPointer.x;
fullSpotPointer.y = emptySpotPointer.y;
if(emptySpotPointer.x == 0){
emptySpotPointer.x = rowSize - 1;
emptySpotPointer.y--;
} else {
emptySpotPointer.x--;
}
}
function removeItem(inputX:int, inputY:int):void {
if(unsortedMap[inputY][inputX] == 0){
trace("removeItem() - No item here to remove: "+ inputX +", "+ inputY);
return;
}
trace("removeItem() - Removing an item here: "+ inputX +", "+ inputY);
unsortedMap[inputY][inputX] = 0;
sortedMap[fullSpotPointer.y][fullSpotPointer.x] = 0;
if(fullSpotPointer.x == (rowSize - 1)){
fullSpotPointer.x = 0;
fullSpotPointer.y++;
} else {
fullSpotPointer.x++;
}
}
// testing stuff here
// -----------------------------------------------------------------
function addRandomitems():void {
var randomX:int = Math.floor(Math.random() * rowSize);
var randomY:int = Math.floor(Math.random() * rowCount);
addItem(randomX, randomY);
}
function removeRandomitems():void {
var randomX:int = Math.floor(Math.random() * rowSize);
var randomY:int = Math.floor(Math.random() * rowCount);
removeItem(randomX, randomY);
}
print2dArray("unsortedMap", unsortedMap);
print2dArray("sortedMap", sortedMap);
trace("Test: Adding items now ---------------------");
var counter:int = 0;
for(counter = 0; counter < 50; counter++){
addRandomitems();
print2dArray("unsortedMap", unsortedMap);
print2dArray("sortedMap", sortedMap);
}
trace("Test: Removing items now ---------------------");
for(counter = 0; counter < 50; counter++){
removeRandomitems();
print2dArray("unsortedMap", unsortedMap);
print2dArray("sortedMap", sortedMap);
}
Third attempt:
import flash.utils.getTimer;
var myMap:Array = [
[1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0],
[1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0],
[1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0],
[1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0],
[1,0,0,0,0,0,1,1,0,1,1,0,0,1,1,0,0,0,0,0]
];
function sort(inputArray:Array):Array {
var rowSize:int = inputArray[0].length;
var flat:Array = new Array();
// flattening the array here
for(var row:String in inputArray){
flat = flat.concat(inputArray[row]);
}
flat.sort();
var result:Array = new Array();
// recreating the original array here by cutting out 'rowSize' chunks and reforming the 2d array
while(flat.length > 0){
result.push(new Array(flat.splice(0, rowSize)));
}
return result;
}
// testing
var startTimer:int = flash.utils.getTimer();
for(var counter:int = 0; counter < 10000; counter++){
sort(myMap);
}
// Running the above 10,000 times takes 1836ms for me.
trace(flash.utils.getTimer() - startTimer);
// just to see the output:
trace(sort(myMap).join("\n"));

AS3: How do I hittest objects in one array with objects in another array

From what I understand:
If I want to hittest two non-array objects, the code would be:
if(player.hitTestObject(enemy))
{
}
The same code would also work if I was testing a non-array object with every object in an array.
But what do I do if I want to hittest every object in one array with every object in a second array?
Here's a resource-friendly one, if all you want to know is whether ANY of the items hit ANY other item:
public function anyItemWasHit( arr1:Array, arr2:Array ) : Boolean {
for each( var item:DisplayObject in arr1)
if( itemHitArrItem( item, arr2 ) )
return true;
return false;
}
private function itemHitArrItem( item:DisplayObject, arr:Array ) : Boolean {
for each( var arrItem:DisplayObject in arr )
if( item.hitTestObject( arrItem ) )
return true;
return false;
}
Based on the previous example, here's one that returns an array of ALL items that hit ANY other item:
public function itemsThatHitOtherItems( arr1:Array, arr2:Array ) : Array {
var items:Array = [];
for each( var item:DisplayObject in arr1 )
if( itemHitArrItem( item, arr2) )
items[items.length] = item;
return items;
}
And, finally, one that returns an array of all pairs (the item that hit another item, AND the item that was hit):
public function allPairsThatHitEachOther( arr1:Array, arr2:Array ) : Array {
var pairs:Array = [];
for each( var item:DisplayObject in arr1 ) {
var itemPairs:Array = allPairsForItem( item, arr2 );
if ( itemPairs.length > 0 )
pairs = pairs.concat( itemPairs );
}
return pairs;
}
private function allPairsForItem( item:DisplayObject, array:Array ) : Array {
var pairs:Array = [];
for each( var otherItem:DisplayObject in array )
if( item.hitTestObject( otherItem ) )
pairs[pairs.length] = [item, otherItem];
return pairs;
}
I'm guessing you're really just asking about the syntax. In this case it would be:
where:
indexOne goes from 0 to arrayOne.length - 1 (can be in a for loop)
indexTwo goes from 0 to arrayTwo.length - 1 (can also be in a nested for loop)
arrayOne[indexOne].hitTestObject(arrayTwo[indexTwo])
outerLoop: for (var i:int = 0; i < arr1.length; i++) {
var obj1:DisplayObject = arr1[i] as DisplayObject;
for (var j:int = 0; j < arr2.length; j++) {
var obj2:DisplayObject = arr2[j] as DisplayObject;
if (obj1.hitTestObject(obj2)) {
// these 2 hit each other
break outerLoop;
}
}
}