so i have an array containing many instances. let's say movieclips.
and i have another array which contains numbers..in this case those numbers represent selected indices that i've somehow chosen!
var manydots:Array = new Array ();
for (var i=0; i<10; i++)
{
var newDot:dot = new dot ;
manydots.push(newDot);
}
var indices:Array = [0,1,5,8,4]
i want to use AddChild to add those movieclips into my scene, but not all of them, only selected indices contained in my 2nd array
I think this is what you are looking for,
for (var j=0; j<indicies.length; j++) {
addChild(manyDots[incidies[j]]);
}
sberry solution is correct. But you may also want to check that you actually are not adding null as a child.
for each(var i:int in indices) {
if (i < manydots.length) {
var d:dot = manydots[i];
if (d) {
addChild(d);
}
}
}
Related
I am developing a game that has a winning combination array:
var allwinning = [
['000','010','020'],
['000','100','200'],
['000','001','002'],
['000','101','202'],
['000','011','022'],
['000','110','220']];
The player will need to pick more than 3 numbers randomly. If all numbers are within any of the combinations in allwinning, the player wins.
For example, if the player picks '111','110','000','220', the player will win because allwinning[5] has the combination['000','110','220'].
My question is, what is the best way to do this winning loop? I cannot figure out the optimum way to do this.
Currently, I have a playerpick array to keep what player had picked and possiblewin array:
var playerpick = new Array(['111','110','000','220']);
var playerpicksingle = playerpick[0];
var possiblewin = new Array([]);
Then I go through a loop to capture out the possible win combination first:
for(var i=0 ; i < allwinning.length - 1 ; i++)
{
for(var j=0 ; j <3 ; j++)
{
if(allwinning[i][j]==playerpicksingle)
{
possiblewin.Push(allwinning[i]);
}
}
}
Then I am stuck at this point. I really don't know what else to do.
I can think of two ways. One requires you to change your data structure and the other doesn't.
Without changes:
Sort the user input:
pickedNumbers.sort();
and start comparing. By sorting the values beforehand you know when you can back out and continue with the next set of numbers, i.e. you can back out early and don't have to compare all the values (in the average case).
function wins(picked, winning) {
var winningSet = [];
for (var i = 0; i < winning.length && winningSet.length < 3; i++) {
var set = winning[i];
winningSet = [];
var j = 0;
var k = 0;
while (j < set.length && k < picked.length && winningSet.length < 3) {
if (picked[k] === set[j]) {
winningSet.push(set[j]);
j++; // advance to next element in winning set
} else if (picked[k] > set[j]) {
// continue with the next set
break;
}
// maybe the next element in players picks will match
k++;
}
}
return winningSet.length === 3 ? winningSet : false;
}
The worst case scenario of this solution is O(n*m*l), but since the input is sorted, the average case will be better.
DEMO
With Array#some and Array#every the code becomes much more concise, though it looses the advantage of using sorted input. If your arrays are small it won't make a difference though:
function wins(picked, winning) {
return winning.some(function(set) {
return set.every(function(val) {
return picked.indexOf(val) !== -1;
});
});
}
It also won't give you the actual numbers that matched. The runtime is the same.
The second way would be to build some kind of trie instead of using an array of arrays:
var allwinning = {
'000': {
'010': {
'020': true
},
'100': {
'200': true
},
// ...
}
};
The structure should also be sorted, i.e. the keys of a level are all smaller then the keys of its sublevel etc.
Sort the user input as well and iterate over it. Whenever you found a matching key, you go one level deeper until you have three matches:
function wins(picked, winning) {
var winningSet = [];
for (var i = 0; i < picked.length && winningSet.length < 3; i++) {
if (picked[i] in winning) {
winningSet.push(picked[i]);
winning = winning[picked[i]];
}
}
return winningSet.length === 3 ? winningSet : false;
}
This solution has the worst case scenario of O(n), where n is the number of values the user picked (not taking into account the time it takes to test whether an object contains a specific property name. Often this is assumed to constant).
DEMO
So I am building a deck of cards. I have them blocked out, and appearing correctly on the screen. Now I need to build an array with numbers 1-16, and display them randomly on the cards without duplicating any numbers. My main problem is I can't figure out how to display the random numbers on the cards. I have filled the array, got the cards displaying correctly, I can even display the numbers in order, but can't figure out the code to display the numbers randomly. Thanks in advance.
Below is the code I have so far, which displays the cards with numerically ordered numbers.
var numberOfColumns=8;
var cardNumber:Array = new Array();
//---"for" function to display card columns---\\
for(var i:int = 1; i < 17; i++) {
var card = new Card();
cardNumber[i]= i;
card.x = ((i-1) % numberOfColumns) * 70;
card.y = (Math.floor ((i-1)/numberOfColumns) * 80);
card.cardTxt.text = i;
trace(i);//trace card count in Output
addChild(card);//add object to display list
}
trace(cardNumber);
One solution ( definetly not the best ) would be to fill another array with only indexes and then randomly splice it, like this :
var cardCount:int = 17;
var indexesArray:Array = [];
for(var j:int = 1; j < cardCount; j++)
indexesArray.push(j)
for(var i:int = 1; i < cardCount; i++) {
var card = new Card();
//Use a random index inside the array length
var randIndex:int = Math.round(Math.random()*indexesArray.length);
cardNumber[i]= indexesArray[idIndex];
//Strip out our used index so we can't use it again
indexesArray.splice( randIndex, 1 );
//... your code
}
However I'm pretty sure some logic freak can come up with a more optimized/clean solution, and avoid the need for a second array.
Is this possible? For example, if I had 100 items named item1.....item100, could I add them all to an array using a loop? Something along these lines....but this doesn't work obviously:
for (var i:int = 1; i <= 100; i++)
{
myArray.push("label" + 1);
}
Luckily I only have 10 items, so I can do it manually, but I'm just curious for future reference...
Thanks!
The array access operator will let you reference properties and objects by name like that, so if you have:
myArray.push(label1);
You can use this instead:
myArray.push(this["label" + 1]);
Depends on on you mean by "items".
If they are properties of the current class use:
for (var i:int = 1; i <= 100; i++)
{
myArray.push(this["label" + i]);
}
You can do this even if the names of the objects do not follow any particular pattern but they have to be inside a 'container' (you will add all objects from the container to the array):
for (var i:int = 0; i < containerName.numChildren; i++)
{
myArray.push(containerName.getChildAt(i);
}
You have to get the link to the object instance to push it into the array, for example if the names of your text fields are label1, label2, etc. you can use the following code:
for (var i:int = 1; i <= 100; i++)
{
myArray.push(labelsContainer.getChildByName("label" + i));
}
I have two arrays, namely combo and truecombo. The user fills the combo with MovieClips by clicking on various buttons on the stage, truecombo is the correct combination.
At any given point (enterFrame) Flash is checking whether the two are the same, if yes, then do some stuff. For the time being this is my code (altered several times, like with Typecasting the indices, adding .parent at the end of combo[o] etc. 2 things will happen, either one or the other.
Either the statement will not be satisfied, at which point the adding and chopping of the combo array will continue, or the condition will be instantly met when combo.length = 6. Check my code.
UPDATE: I have a dropbox file with my current code. Click this for FLA link and here is the SWF link stripped down as always for ease and security.
/*stage.*/addEventListener(Event.ENTER_FRAME, checkthis);
function checkthis(e:Event)
{
for(var o:int=0;o<= combo.length; o++)
{
if((combo[o] == truecombo[o]) && (combo.length==truecombo.length))
{
equal=true;
}
}
if (equal==true)
{
stage.removeEventListener(Event.ENTER_FRAME, checkthis);
endSeq();
}
}
function endSeq():void
{
bravo.play();
for (var i:int = 0; i < combo.length; i++)
{
var element:DisplayObject = combo[i];
element.parent.removeChild(element);
}
firebb.gotoAndPlay(2);
windbb.gotoAndPlay(2);
spiritbb.gotoAndPlay(2);
earthbb.gotoAndPlay(2);
}
This is how I push my new elements to the combo array.
function add(element:DisplayObject)
{
twist.gotoAndPlay(2);
element.width = WIDTH;
element.height = HEIGHT;
if (this.combo.length >= MAX_ELEMENTS)
{
removeChild(this.combo.shift());
}
this.combo.push(element as DisplayObject);
this.addChild(element);
this.reorder();
}
function reorder()
{
for (var i:int = 0; i < combo.length; i++)
{
var element:DisplayObject = combo[i];
element.x = OFFSET_X + (i * SEP_X);
element.y = OFFSET_Y;
}
}
And this is how I have my truecombo and its contents created.
var fireb:firebtn = new firebtn();
var spiritb:spiritbtn = new spiritbtn();
var earthb:earthbtn = new earthbtn();
var windb:windbtn = new windbtn();
var combo:Array=new Array();
const truecombo:Array = [fireb,windb,spiritb,windb,earthb,fireb];
Sorry for the lack of comments, I'd guess it's pretty self-explanatory. Thanks in advance.
I believe combo[o] & truecombo[o] are two instances of the same class & you want them to be matched. If that is the case you may consider :
getQualifiedClassName(combo[o]) == getQualifiedClassName(truecombo[o])
To match the way you did, you must ensure the objects lying inside truecombo be referring to the same ones on stage & not new instances.
EDIT:
It seems you do not break the loop when the match is a success. Use this instead :
function checkthis(e:Event)
{
for(var o:int=0;o<= combo.length; o++)
if((combo[o] == truecombo[o]) && (combo.length==truecombo.length)) {
equal=true;
break;
}
if (equal) {
stage.removeEventListener(Event.ENTER_FRAME, checkthis);
endSeq();
}
}
Here's a really simple loop:
var equal:Boolean=true
if(combo.length == truecombo.length) {
for(var i:int=0; i<combo.length; i++) {
if(combo[i] != truecombo[i]) {
equal=false;
break;
}
}
} else {
equal=false;
}
if(equal) {
//do whatever
}
This assumes both are equal, until we find out otherwise. So if the lengths are different, they are not equal. If the ith element is different, they are not equal.
In the end, you check if your flag equal is true and do whatever you want to do.
I have an array of sprites called segments and I would like to skip the first element of segments in my for each loop. I'm doing this at the moment:
var first = true;
for each (var segment in this.segments)
{
if(!first)
{
// do stuff
}
first == false;
}
Is there a better way to do this? Thanks!
if its an array why not just:
for(var i:int = 1; i < this.segments.length; i++)
{
}
This can also be done via "slice".
For example
for (var segment in this.segments.slice(1))
{
}
Array#slice will copy the array without the first element.