Use of for-loop to create a stair of ellipses

Sorry to be such a pain.

let’s say one for-loop says

  • put a circle at 1st column of row 1, then
    
  • a circle at 2nd column of row 1 and
    
  • 3rd of row 1…
    

You fill ONE row this way.

How many times must you repeat this for-loop??

As many rows you want to have!!

BUT how do you repeat this for-loop?

By copying it in your Code several times…??

NO… But by using a 2nd for loop!!!

2 Likes

Hi @Jayda,

Execute the code below. Though it will not draw your pattern, it exemplifies a common pattern regarding nested loops that may serve as a hint.

function setup() {
  for (let i = 1; i <= 4; i++) {
    alert("row " + i + " . . .");
    for (let j = 1; j <= i; j++) {
      alert("i = " + i + ", j = " + j);
    }
  }
}

Note from the details of the code and the output how the outer loop controls the inner loop.

3 Likes

my code

int w = 20, scl = 20;
size(600,600);
background(0);
for(int j = 0; j < w; j++) {
  for(int i = 0; i < j; i++) {
    ellipse( (i+0.5)*scl, (j+0.5)*scl,scl,scl);
  }
}

2 Likes

You can also do something like this:

int w = 10, scl = 20;
size(600,600);
background(0);
for(int j = 0; j < w; j++) {
  for(int i = 0; i < j*2; i++) {
    ellipse( (i+0.5)*scl, (j+0.5)*scl,scl,scl);
  }
}

edit: or this!

int w = 30, scl = 20;
size(600,600);
background(0);
for(int j = 0; j < w; j++) {
  for(int i = 0; i < j/2; i++) {
    ellipse( (i+0.5)*scl, (j+0.5)*scl,scl,scl);
  }
}

1 Like

btw how to tag a post as spoiler? I don’t want to show the code directly if the OP doesn’t want

1 Like

Haha! Good point! I think the OP solved it.

But anyway you can leave your posts like they are.

For future posts: the idea is that this is an educational forum so we encourage others to find their solution.

So normally we won’t post full code solutions.

Especially when it’s homework and not hobby

But as I said it’s okay here!

So thank you!

Impressive work that you do by the way in your projects, especially Lissajous!

Warm regards,

Chrisir

3 Likes

When I was just staring coding after seeing the coding train youtube channel I didn’t know too much. The videos that were not “introductions to xyz” were too hard for me. So I wanted to see it from actual examples. It is the fastest way to learn for me since I am self-tought. Whenever I posted a post on this forum I wanted an actual solution instead of hints. And my english was far worse than what it is now so I couldn’t really understand the hints. I kept in mind what I wanted so I am posting the whole code. Well somebody reccomended to create my own page where I’ll post all my creations.

Btw what do you think when you said Lissajous was impressive? The project was far below and took me far less time than things like FloodIT. I don’t really understand.

2 Likes

I liked Lissajous because it looked so cool, the different types on one page! Just great!

well it’s just the usual lissajous tables. I’ve seen the coding train making it in a grid too

1 Like

Below is a portion of a solution in p5.js that utilizes the translate, push, and pop functions to simplify the math. To complete the draw function, you’ll need to precede this code with an assignment to the diam variable to specify the size of the ellipses, and an initial call to translate in order to make sufficient room along the top and left margins.

See the comments for explanations.

  // draw the stair of ellipses
  for (let row = 0; row < 20; row++) {
    push(); // save coordinate system at beginning of row
    for (let col = 0; col <= row; col++) {
      ellipse(0, 0, diam);
      // position coordinate system for next column in current row
      translate(diam, 0);
    }
    pop(); // restore coordinate system from beginning of row
    translate(0, diam); // position coordinate system for next row
  }

Edited on December 16, 2020 to insert an additional comment into the code.

1 Like

Below is code for a variant of the project that uses a different approach. It is written for the Processing Python Mode .

Note that the code does not contain any for loops. Instead, it uses recursion, whereby a function calls itself. The concept behind this approach is that we can build a large object from smaller versions of itself. For example, to build a staircase of n steps, we can build a large step, then build a smaller staircase of n - 1 steps on top of that step. The smallest staircase is one that consists of only one step.

Here’s a picture of the result:

The code is below. See the comments for explanations. As a challenge, try to draw the above by translating the code into p5.js.

Also see Wikipedia: Recursion.

def setup():
  size(440, 440)
  noLoop()
  background(249)
  fill(0, 0, 0, 48)
  
def draw():
  # Draw a staircase with 16 stairsteps composed of
  # round building units with a diameter of 40.
  diam = 40
  dimension = 10
  draw_staircase(diam, height - diam, diam, dimension)

# Three recursive functions follow.
# A recursive function is one that calls itself.
# Each recursion consists of ...
#   a recursive case wherein the function calls itself.
#   a base case wherein the function does not call itself.

# To avoid an infinite recursion, the recursive calls must ultimately resolve to the base case.

# Within the three recursions here ...
#   The recursive cases build features from smaller versions of themselves.
#   The base cases draw the smallest versions of the features.

def draw_building_unit(x, y, diam):
  if diam > 5:
    # Recursive case: 
    # First, draw a smaller round building unit.
    draw_building_unit(x - diam // 16, y - diam // 16, diam * 3 // 4)
    # Then enclose it in a full-size ellipse.
    ellipse(x, y, diam, diam)
  else:
    # Base case: simply draw a small ellipse
    ellipse(x, y, diam, diam)

def draw_step(x, y, diam, dimension):
  # First, draw a round building unit.
  draw_building_unit(x, y, diam)
  # If <dimension> > 1, extend the step toward the right 
  # by a smaller step with <dimension - 1> round building units.
  if (dimension > 1):
    draw_step(x + diam, y, diam, dimension - 1)
    
def draw_staircase(x, y, diam, dimension):
  # First, draw a step of <dimension> circles.
  draw_step(x, y, diam, dimension)
  # If <dimension> > 1, draw a smaller staircase
  # of <dimension - 1> steps on top of it.
  if dimension > 1:
    draw_staircase(x, y - diam, diam, dimension - 1) # recursive case
  else:
    pass # Base case; do nothing
2 Likes

So cool !
I try it on P5.js

How should I made this with only nested loop
Untitled

I can just make this

1 Like

It is better to use x,y in this case instead of i,j

What do you think why this is?

You can rename by right click on the j for example and choose Rename from the local menu. I use it all the time.

What to do

You are almost there. Where do you think is the problem? Which line? What values do you want to generate?

How can you modify the line?

2 Likes

Hello, @yoyo, and welcome to Processing Foundation Discourse!

It is best to post code as text, rather than as an image capture. Code, as text, is easy for others to copy and paste, so that they can test and experiment with it.

Please also format code when you post it, so that it is easy for others to read. For information on all of this, see Guidelines—Asking Questions.

Following is your code as text, formatted for posting, and with the names the variables i and j changed to x and y, respectively:

function setup() {
  createCanvas(400, 400);
  background(0);
  for (let x = 0; x <= 20; x++) {
    for (let y = 0; y <= x; y++) {
      circle((x + 0.5) * 20, (y + 0.5) * 20, 20);
    }
  }
}

function draw() {
}

Examining the code, including the ranges of the values of the loop variables and the size of the canvas, do you think some circles are being drawn that are outside the canvas? How can you find out?

To figure out how to draw the staircase as you would like it, consider how the values of x in the outer loop should be used to control the range of values of y in the inner loop. Consider what values of y are needed when x is 5 or 15, for example. How can you modify the code to make that happen? Think about the inner loop.

1 Like

Hello. As advised, try to understand what you need to do and what you are doing…
To help you here, the same code added some debug info. Run and look to the canvas and the console output.

function setup() {
  createCanvas(400, 400);
  background(0);
  let number = 0
  const diameter = 20;
  const wanted_x = 0 + diameter / 2;
  const wanted_y = height - diameter / 2;
  fill("red");
  ellipse(wanted_x, wanted_y, diameter);
  logDebug1(wanted_x,wanted_y);
  noFill();
  stroke(255);
  textSize(8);
  for (let x = 0; x <= 20; x++) {
    for (let y = 0; y <= x; y++) {
      logDebug2(x, y);
      const xp = (x + 0.5) * 20;
      const xy = (y + 0.5) * 20
      circle(xp, xy, 20);
      
      text(number, xp - 5, xy +5);
      number++;
    }
  }
}

function logDebug1(wanted_x,wanted_y) {
  console.log(`my ideal first circle is red and draw, (by hard code) at:
xpos = ${wanted_x}
ypos = ${wanted_y} `);
}

function logDebug2(x, y) {
  if (x === 0) {
    console.log(`my first cricle is draw at:
xpos = ${(x + 0.5) * 20}
ypos = ${(y + 0.5) * 20}\n`);
  } else if (x === 20) {
    console.log(`my last circle was draw at:
xpos = ${(x + 0.5) * 20}
ypos = ${(y + 0.5) * 20}
my window is 400x400...`);
  } else {
    console.log(
      `Those are al positions I'm drawing with;
when x = ${x} and y = ${y}
xpos = ${(x + 0.5) * 20}
ypos = ${(y + 0.5) * 20}\n`
    );
  }
}

1 Like

Hello again, @yoyo.

We hope you are making progress with this project. Please let us know how you are doing with it.

If you run @vkbr’s code, which provides information for debugging, observe the output in the console, especially the final output. For circles to appear on the canvas, their coordinates must be within the proper boundaries. Note the size of your canvas and, in the output, the locations of the circles that are being drawn.

1 Like

Hmm, how about a solution with only one for-loop?
The downside is it does some unnesesary stuff…

// side defines the width of an ellipse
for (let i=0; i<side*side; i++) {
    // check if ellipse shoud be drawn
    if (floor(i/side) < (i % side)) {
        // position of ellipse 
        ellipse(floor(i/side) * side, (i % side) * side, side, side
    }
  }
1 Like

A solution with one loop is a great idea. For whatever the reason is, @yoyo would like to do it with a nested loop, as stated here:

@philipplehmann, this line needs to be edited for it to work:

        ellipse(floor(i/side) * side, (i % side) * side, side, 10side

@yoyo, if some of the circles are outside the bounds of the canvas, you can correct that by changing the upper limit of the variable in the outer loop, which you have as 20. Perhaps it needs to be just a little bit smaller.

Then you can achieve the correct configuration of the staircase by revising the header of the inner loop. Think about what values of the variable are needed in the inner loop header with relation to each value of the other variable in the outer loop header.

1 Like