00:00
00:00
Newgrounds Background Image Theme

Someone gifted MetalSlayer69 supporter status!

We need you on the team, too.

Support Newgrounds and get tons of perks for just $2.99!

Create a Free Account and then..

Become a Supporter!

AS2 Nested For Loops

520 Views | 4 Replies
New Topic Respond to this Topic

AS2 Nested For Loops 2023-03-18 20:18:46


**Take a look at this fla, pretty please.


I was looking at an ancient physics example that had a snippet of code that nested for loops (you can look at it here) and tried quickly and sloppily recreating it for myself. One thing I noticed is that under conditional statements like...

if(bub[j].hitTest(bub[k])) {
    trace("touch");
    if(bub[i].d == 1) {
      bub[i]._y += 50;
    }
}

...is that the output is enacted on all movieClips that have "d" set to "1" not just that single movieClip hitting the other movieClip.


In a more thorough fla I created (you can preview it here or download the raw fla here) with no super specific conditional statements, it seems to work just fine. Outputs of movieClips colliding with each other were only enacted on just those two movieClips and not everything else in the array. So now I'm really confused about how this actually works. Is it only applicable under broad if statements? What else can I do with nested for loops?


[1] - [2]

Response to AS2 Nested For Loops 2023-03-19 00:21:09 (edited 2023-03-19 00:35:34)


I'm not sure what you're trying to ask here, so I'll answer the question of "why are all the balls whose 'd' variable is 1 moving in the first fla you posted". It's because you're selecting them all. It might sound like a copout, but think about it in another way: for (loops) define what you want to select, and if (conditions) within these for loops define what to filter. If you have three independent variables, then you're selecting three different sets/populations of items (depending on what you do with those variables).


It might help if you rearrange the loop order. Let's put the i = .... as the innermost loop; here's the original code:

for(i = 0; i < bub.length; i++) {
    for(j = bub.length-1; j >= 1; j--) {
        for(k = j-1; k >= 0; k--) {
            if(bub[j].hitTest(bub[k])) {
                trace("touch");
                if(bub[i].d == 1) {
                    bub[i]._y += 50;
                }
            }
        }
    }
}


Now let's rearrange it:

for(j = bub.length-1; j >= 0; j--) { //>= 0 - not sure why >= 1
    for(k = j-1; k >= 0; k--) {
        if(bub[j].hitTest(bub[k])) {
            for(i = 0; i < bub.length; i++) {
                trace("touch");
                if(bub[i].d == 1) {
                    bub[i]._y += 50;
                }
            }
        }
    }
}


You can probably see why this would move all the items whose "d" variable is 1 - because you're looping over the entire array again; in effect, whenever a single object touches another, then you look at all the items in the array whose d value is 1 and move them. If you remove the innermost loop, and you change the i to a k, then you'll get something closer to desired behaviour, of the current (i.e. the kth) object only moving if its d variable is 1:

for(j = bub.length-1; j >= 0; j--) {
    for(k = j-1; k >= 0; k--) {
        if(bub[j].hitTest(bub[k])) {
            trace("touch");
            if(bub[k].d == 1) {
                bub[k]._y += 50;
            }
        }
    }
}


It might help if you look at the visualization of bubble sort (ignore the insertion sort and focus only on how the bubble sort is carried out, by comparing one element with all others and swapping as necessary)


With its corresponding implementation:

function bubbleSort(arr, n) {
    for (i = 0; i < n-1; i++) {
        for (j = 0; j < n-i-1; j++) {
            if (arr[j] > arr[j+1]) {
                var temp = arr[xp];
                arr[xp] = arr[yp];
                arr[yp] = temp;
            }
        }
    }
}

Slint approves of me! | "This is Newgrounds.com, not Disney.com" - WadeFulp

"Sit look rub panda" - Alan Davies

BBS Signature

Response to AS2 Nested For Loops 2023-03-19 01:32:25


At 3/19/23 12:21 AM, Gimmick wrote: I'm not sure what you're trying to ask here, so I'll answer the question of "why are all the balls whose 'd' variable is 1 moving in the first fla you posted". It's because you're selecting them all. It might sound like a copout, but think about it in another way: for (loops) define what you want to select, and if (conditions) within these for loops define what to filter. If you have three independent variables, then you're selecting three different sets/populations of items (depending on what you do with those variables).

It might help if you rearrange the loop order. Let's put the i = .... as the innermost loop; here's the original code:

Now let's rearrange it:

You can probably see why this would move all the items whose "d" variable is 1 - because you're looping over the entire array again; in effect, whenever a single object touches another, then you look at all the items in the array whose d value is 1 and move them. If you remove the innermost loop, and you change the i to a k, then you'll get something closer to desired behaviour, of the current (i.e. the kth) object only moving if its d variable is 1:

It might help if you look at the visualization of bubble sort (ignore the insertion sort and focus only on how the bubble sort is carried out, by comparing one element with all others and swapping as necessary)

With its corresponding implementation:


Honestly, I don't really know what I'm doing myself, but I'm still really glad you're here lurking the forums to straighten things out whenever I'm having trouble understanding something, like that time with function parameters a few months earlier.


[1] - [2]

Response to AS2 Nested For Loops 2023-03-19 01:40:15 (edited 2023-03-19 01:51:02)


At 3/19/23 12:21 AM, Gimmick wrote:
It might help if you look at the visualization of bubble sort (ignore the insertion sort and focus only on how the bubble sort is carried out, by comparing one element with all others and swapping as necessary)

With its corresponding implementation:


Oh my God, this video is making my brain melt.


But like, thank you for exposing it to me.


[1] - [2]

Response to AS2 Nested For Loops 2023-03-20 04:32:12 (edited 2023-03-20 04:38:00)


At 3/19/23 01:32 AM, Nabella wrote: Honestly, I don't really know what I'm doing myself, but I'm still really glad you're here lurking the forums to straighten things out whenever I'm having trouble understanding something, like that time with function parameters a few months earlier.


No worries, my pleasure! If you have trouble with nested loops, maybe it would help to experiment with different levels and maybe express it in different concepts. For example, perhaps you might find converting it to a set representation.


Suppose you have an array of 10 numbers:

var arr:Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

Then, a single loop would be the equivalent of operating over the entire array:

for (var i:Number = 0; i < arr.length; i++) {
    //code
}

iu_926527_2555669.png

If you add an if condition, then that narrows down your set, e.g. all numbers less than 5:

for (var i:Number = 0; i < arr.length; i++) {
    if (arr[i] < 5) {
        //code
    }
}

iu_926528_2555669.png

That's fairly normal, but suppose you wanted to get the cumulative sum for all elements, such that

1, 2, 3, 4, 5, 6, 7, 8, 9, 10

becomes

1, 3, 6, 10, 15, 21, 28, 36, 45, 55

for the sake of illustration, let's ignore the efficient method of keeping track of the current running total and let's just calculate the cumulative sum from scratch each time. You're going to go over all the elements before the one that's currently visited, so the code will look something like this:

var cumulatives:Array = []
for (var i:Number = 0; i < arr.length; i++) {
    var sum:Number = 0
    for (var j:Number = 0; j < i; j++) {
        sum += arr[j];
    }
    cumulatives.push(sum)
}

which is almost equivalent to

for (var i:Number = 0; i < arr.length; i++) {
    var sum:Number = 0
    for (var j:Number = 0; j < arr.length; j++) {
        if (j < i) {
            sum += arr[j]; // bonus: why j and not i?
        }
    }
    cumulatives.push(sum)
}

Because there are two iteration variables, i and j, you can imagine duplicating the set of numbers into two. Let's label them i and j for each of the loops:

iu_926529_2555669.png

However, because i and j are linked together with the loop condition j < i, you're effectively selecting a different subset each time i changes:

iu_926530_2555669.png

And then finally, for a given subset you calculate the sum and add that to the cumulatives array:

iu_926531_2555669.png

I can't really think of a way to decide whether you need a nested loop beyond experience, but a good starting point, I suppose, would be to ask:

  • how am I going to get access to this item? [with a new loop]

Because at the root of it all, with a single loop, you can map*, or get access to all the elements in the set, but you only have access to them one at a time. With nested loops, you can have access to the original element you were "holding", as well as an entire set of items again, but with access to those elements one at a time as well. That's why we used a variable to store the cumulative sum at each stage, because we can only access the elements of the set one by one even in the inner loop. In other words, we're reducing the inner set (j) into the sum of all the elements it covers.


Whether you need to reduce or not depends on the task at hand. For finding the cumulative sum, we needed to reduce all the elements in the inner loop into one item. But in the case of a sorting operation, or a collision detection problem, there's no reduction involved - just accessing/mapping. Take the collision detection example - we need to check if all the balls collide with each other. Let's ask the question from earlier.

  • How am I going to get access to [each ball in the array]?

You need 1 loop variable to get access to each ball in the array.

for (var i:Number = 0; i < balls.length; ++i) {
    var ball = balls[i] // a single ball
}

We now want to check whether this ball collides with the rest. How do we get access to the other balls? With a nested loop. You can't use a separate one because then you no longer have access to "each" ball, only the last one:

for (var i:Number = 0; i < balls.length; ++i) {
    var ball = balls[i] // a single ball
}
for (var j:Number = 0; j < balls.length; ++j) {
    var otherBall = balls[j]
    if (ball.hitTest(otherBall)) {
        trace("hit") // won't work as expected - "ball" only refers to last ball in balls array
    }
}

So if you use a nested array, you now have access to all the balls, as well as the current ball. But because "all the balls" also includes the current ball, you have to exclude the current ball by adding that condition:

for (var i:Number = 0; i < balls.length; ++i) {
    var ball = balls[i] // a single ball
    for (var j:Number = 0; j < balls.length; ++j) {
        var otherBall = balls[j]
        if (ball != otherBall) { // excludes "ball" from the set of balls to check for collision
            if(ball.hitTest(otherBall)) {
                trace("hit") // works now
            }
        }
// n.b. above two ifs usually written as "if (ball != otherBall && ball.hitTest(otherBall)) {}"
    }
}

*mapping in programming generally refers to a function that transforms the elements of one array into another, but here I am using the definition, "to collect".


At 3/19/23 01:40 AM, Nabella wrote: Oh my God, this video is making my brain melt.

But like, thank you for exposing it to me.

It's missing the earlier context where they first introduced bubble sort (which was covered in previous videos), so maybe it's not the best. But if visualizations help, then you might find better videos on youtube covering nested loops.


Also, I can't think of very many situations where you need three nested loops. They do exist (e.g. in matrix multiplication - can you see why?) but they're rare, so reconsider if you really need three loops for a particular task.


Slint approves of me! | "This is Newgrounds.com, not Disney.com" - WadeFulp

"Sit look rub panda" - Alan Davies

BBS Signature