Use of for-loop to create a stair of ellipses

cool! I am trying this

I have tried the different combinations on x and y. but it’s just made this stair of ellipses and the stair that I made before with different starting points. How should I make the up stair from left to right?

Sorry guys, I am temporarily limited to 3 replies on the same topic. For adding another reply, I may need to edit my previous replies. So I can’t have a new reply. I’ll edit this reply. BTW thx a lot!!!

@yoyo,

Let’s focus on the two loop headers from your original code.

Following are those two headers, with i changed to x and j changed to y:

  for (let x = 0; x <= 20; x++) {
    for (let y = 0; y <= x; y++) {

If you run the debugging code supplied by @vkbr, and look at the JavaScript console, you will find that your code produces 21 steps, even though your original image showed that you needed only 20. The extra step is not visible in the sketch, because it is being drawn outside your canvas. The problem is that your outer loop iterates 21 times instead of 20. There are 21 numbers in the range 0 to 20, inclusive. That 20 in the outer loop header needs to be 19. Alternatively, you could change the condition to exclude 20.

Each iteration of the outer loop is responsible for one column of circles. The first column needs to have 1 circle, and they must increase by 1 in number in each column that follows. This must occur while the value of x is increasing. We need to make sure to attach the steps to the bottom, instead of to the top of the canvas. If you subtract x from 19 and assign the result to y, and specify that y must be less than or equal to 19, what would happen with the inner loop as x increases by 1 during each iteration of the outer loop?

Hello @yoyo,

Hint:

function setup()
  {
  createCanvas(400, 400);
  textSize(16);
  
  for(let num = 0; num<=9; num++)
    {
    fill(0);
    text(num, num*30, 30);    // Left to right
    text(9-num, num*30, 60)
    text(num, (9-num)*30, 90) // Reverse - Right to left
    }
  }

Tutorial:
4.2: Nested Loops - p5.js Tutorial

:)

1 Like

There’s different ways to do it… In my solution, one for loop goes up and the other goes down…
like: x+=d y-=d`


But I also find nested loops confuse. When I’m lost with them, I usually reduce the number of iterations to a really small one, like 3 or 5 and use text to log the values so its clearer what is happening.
cheers

For thinking about nested loops, it might help to label the circles by column and row.

EDIT (September 29, 2022):

Within each pair of numbers in all of the circles in the sketch, the first number represents the value of the control variable of the outer loop and the second represents the value of the control variable of the inner loop. These are the column and row numbers.

Take a look at the pairs of numbers in the circles in the diagonal. Is there a consistency regarding the sum of the two numbers in the pairs?

Also note the sums of the pairs of numbers below the diagonal. For each one, how does it relate to the sum of the two numbers in the circle in the diagonal above?

Do these observations suggest anything regarding what would be a good header for the inner loop? There are several possibilities that would work.

2 Likes

omg!! I finally get it

3 Likes

thank you guys

4 Likes

Good work, @yoyo!

Also, thanks go to @Chrisir, @vkbr, @glv, and @philipplehmann.

Since you’ve succeeded with a solution, we can now reveal some additional code of our own that applies to the project.

As mentioned earlier, there are multiple ways to achieve this task. For example …

Now, shifting our focus to the diagram here, which displays the column and row coordinate pairs, we can note that on the diagonal, the column and row numbers of each circle add up to 19. Below the diagonal, where the canvas is filled with circles, the two numbers in the coordinate pairs add up to a number greater than 19. In the entire space above the diagonal, where there are no circles, the numbers in the coordinate pairs would add up to a sum less than 19. From those observations, we can derive something like this regarding the nested loops:

  // column numbers from left to right
  for (let col = 0; col <= 19; col++) {
    // row numbers from the bottom up to and including the diagonal
    // for (let row = 19; row >= 19 - col; row--) {
    for (let row = 19; row + col >= 19; row--) {
      circle((col + 0.5) * 20, (row + 0.5) * 20, 20);
    }
  }

The code above could be refactored slightly to be equivalent to solutions that others have proposed.

big thanks to all of you!!!

2 Likes

An animated version, overlapped with a loop all at once version.

const RAD = 20; //radius
let balls = [];
let x = RAD;
let y;
let l = 1; //lines
let now; //timer

function setup() {
  createCanvas(400, 400);
  y = height - RAD;
  //insert first ball
  balls.push(new Ball(x, y, RAD));
  frameRate(10);
}

function draw() {
  background(120);
  //just draw the balls
  for (let i = 0; i < balls.length; i++) {
    balls[i].display();
  }
  //calc x position
  if (x < width - RAD) {
    x += RAD * 2;

    now = millis();
  } else if (y > RAD) {
    // if x out of window and y not
    l += 2;
    y -= RAD * 2;
    x = RAD * l;
  } else if (millis() - now > 1000) {
    //if both out of window
    // draw again in a loop donuts all at once
    fill(120);
    for (let x = width - RAD; x >= RAD; x -= RAD * 2) {
      for (let y = height - RAD; y >= height - RAD - x; y -= RAD * 2) {
        ellipse(x, y, 19);
      }
    }
    noLoop();
  }
  balls.push(new Ball(x, y, RAD));
}

class Ball {
  constructor(x, y, r) {
    this.x = x;
    this.y = y;
    this.r = r;
  }
  display() {
    push();
    noStroke();
    fill(250);
    ellipse(this.x, this.y, this.r * 2);
    pop();
  }
}

2 Likes