# Two Strategies

There are two strategies for arranging items in a grid:

1. Use a single loop to iterate over the number of items; derive the x and y position from the item number.
2. 3. Use a nested loop to iterate over the x positions and, for each x, iterate over the y positions (left sketches). If the item number is required, derive it from the values of x and y (right sketch).
4. # Strategy 1: Deriving the x and y positions from the index

## Review: Arranging items in a line

This builds on

. Here is a sketch from that page:

``````function setup() {
createCanvas(windowWidth, windowHeight);
}

function draw() {
for (let i = 0; i < 30; i++) {
let x = 20 + 50 * i;
circle(x, 100, 40);
}
}``````  The shape position is derived from the loop index, using the function used here.

Note: From here on, the definition of `setup()` is not shown. Each of the following code samples assumes that the sketch also contains a `setup()` function:

``````function setup() {
createCanvas(windowWidth, windowHeight);
}``````

Derive `y` from `i` as well.

``````function draw() {
for (let i = 0; i < 30; i++) {
let x = 30 + 50 * i;
let y = 30 + 10 * i;
circle(x, y, 40);
}
}``````  ## Deriving the column (x position)

Let’s start with the angled line from above, and just look at the x position.

``````function draw() {
for (let i = 0; i < 30; i++) {
let x = 30 + 50 * i;
let y = 30 + 50 * i;
circle(x, y, 20);
}
}``````  Instead of a diagonal line, where each x is greater than the previous x and each y is greater than the previous y, we would like to arrange the items on a grid. Here, each item is labelled with its index number. The x value increases from items 0 to 4, and then it resets back to the left side and increases again to 9, and so on.  We can use the modulo (remainder) operator `%` to chop it into pieces. For an input sequence i = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 etc., the modulo operator `i % 5` produces 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, etc. The sketch then multiples this by 50 to make the result more visible: 0, 50, 100, 150, 200, 0, 50, 100, 150, 200, 0, 50, etc.

Note: A mnemonic for `%` is that it is like division `/` except that its value is what’s left over (the `°`s).

``````function draw() {
for (let i = 0; i < 20; i++) {
let column = i % 5;
let x = 30 + 50 * column;
let y = 30 + 50 * i;
circle(x, y, 20);
}
}``````  ## Deriving the row (y position)

Now let’s compute the y position. Since there are five items per row, the column is just the number of the item divided by five, and rounded down. For an input sequence i = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 etc., dividing by 5 produces 0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, etc. Rounding this down by using `floor()` produces 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, etc.

``````function draw() {
for (let i = 0; i < 20; i++) {
let row = floor(i / 5);
let x = 30 + 50 * i;
let y = 30 + 50 * row;
circle(x, y, 20);
}
}`````` Putting this together:

``````function draw() {
background(100);

for (let i = 0; i < 20; i++) {
let row = floor(i / 5);
let column = i % 5;

let x = 30 + 50 * column;
let y = 30 + 50 * row;

circle(x, y, 20);
}
}``````  # Varying the items

We can use the row and column in other ways. This sketch gives each circle a size that is a function of its row and column.

``````function draw() {
background(100);

for (let i = 0; i < 30; i++) {
let row = floor(i / 5);
let column = i % 5;

let x = 30 + 50 * column;
let y = 40 + 50 * row;

let size = map(row - column, 0, 10, 10, 50);
circle(x, y, size);
}
}``````  # Using a function to draw each cell

Instead of calling `circle`, we can use our own function.

``````function draw() {
background(100);

for (let i = 0; i < 30; i++) {
let row = floor(i / 5);
let column = i % 5;

let x = 30 + 50 * column;
let y = 40 + 50 * row;

myShape(x, y, row, column, i);
}
}

function myShape(x, y, row, column, i) {
let size = map(row - column, 0, 10, 10, 50);
circle(x, y, size);
}``````  The following code replaces just the implementation of the `myShape` function. The code in `draw()` remains exactly the same.

``````function myShape(x, y, row, column, i) {
let size = map(row - column, 0, 10, 30, 40);
circle(x, y, size / 2);
square(x, y, size);
circle(x + size, y, size / 2);
circle(x, y + size, size / 2);
circle(x + size, y + size, size / 2);
}``````  # Strategy 2: Nested loops

An alternative to deriving the row and column from the linear index `i`, is to use a nested loop (one loop inside of another loop) to step through the x and y values, or the row and column numbers, directly.

``````function draw() {
background(100);

for (let row = 0; row < 5; row++) {
for (let column = 0; column < 6; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;

circle(x, y, row, 20);
}
}
}``````

If we need `i` (the index number), we can derive it from the row and column numbers.

``````function draw() {
background(100);

for (let row = 0; row < 5; row++) {
for (let column = 0; column < 6; column++) {
let i = 5 * row + column;
let x = 30 + 50 * column;
let y = 40 + 50 * row;

circle(x, y, 20);
text(i, x, y);
}
}
}``````  Or we can initialize it 0, and increment it each time through the (inner) loop, to keep count of how many items we've drawn.

``````function draw() {
background(100);

let i = 0;
for (let row = 0; row < 5; row++) {
for (let column = 0; column < 6; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;

circle(x, y, row, 20);
text(i, x, y);
}
}
}``````  # Drawing different items at different grid positions

Above, the same shape is drawn at each grid position. We will add a second function, that draws a second shape. First, rename `myShape` to `decoratedSquare`. This doesn’t change the behavior of the sketch, but it will make it more readable once we add the second shape, since then we can use descriptive names instead of `decoratedSquare1` and `decoratedSquare2`.

``````function draw() {
background(100);

for (let row = 0; row < 5; row++) {
for (let column = 0; column < 6; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;

decoratedSquare(x, y, row, column);
}
}
}

function decoratedSquare(x, y, row, column, i) {
push();
translate(x, y);

let size = map(row - column, 0, 10, 30, 40);
circle(0, 0, size / 2);
square(0, 0, size);
circle(size, 0, size / 2);
circle(0, size, size / 2);
circle(size, size, size / 2);
pop();
}``````  Add a second drawing function `circles()` and call it instead.

``````function draw() {
background(200);

for (let row = 0; row < 5; row++) {
for (let column = 0; column < 6; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;

circles(x, y, row, column);
}
}
}

function circles(x, y) {
push();
translate(x, y);

fill('white');
circle(0, 10, 20);
fill('yellow');
circle(10, 10, 20);
fill('green');
circle(10, 0, 20);

pop();
}``````  Now, we can call `circles()` for some cells and `decoratedSquare()` for others.

``````function draw() {
background(100);

for (let row = 0; row < 5; row++) {
for (let column = 0; column < 6; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;

if ((row + column) % 3 > 0) {
circles(x, y, row, column);
} else {
decoratedSquare(x, y, row, column);
}
}
}
}``````  Animate the circles, by incorporating data from `millis()`.

``````function circles(x, y) {
push();
translate(x, y);

let dx = map(cos(millis() / 500), -1, 1, 0, 10);
let size = 30;
fill('white');
circle(0, dx, 30);
fill('yellow');
circle(dx, dx, 30);
fill('green');
circle(dx, 0, 30);

pop();
}``````  # Extracting `grid()` into a function

Let’s extract the code that draws the grid into its own function, so that we can call it several times in order to create several grids.

``````function draw() {
background(200);
for (let row = 0; row < 5; row++) {
for (let column = 0; column < 6; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;

circles(x, y, row, column);
}
}
}``````

``````function draw() {
background(200);
grid();
}

function grid() {
for (let row = 0; row < 5; row++) {
for (let column = 0; column < 6; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;

circles(x, y, row, column);
}
}
}``````

Change `rows` and `columns` from literal numbers `5` to parameters. This allows the function that calls `grid()` to specify the number of rows and columns.

``````function draw() {
background(200);
grid(5, 6);
}

function grid(rows, columns) {
for (let row = 0; row < rows; row++) {
for (let column = 0; column < columns; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;

circles(x, y, row, column);
}
}
}``````

Call `grid()` twice, to draw two grids of different sizes.

``````function draw() {
background(200);
grid(5, 6);

translate(width / 2, height / 2);
grid(3, 4);
}

function grid(rows, columns) {
for (let row = 0; row < rows; row++) {
for (let column = 0; column < columns; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;

circles(x, y, row, column);
}
}
}``````  # Appendix I: Higher-Order Programming

Higher-Order Programming involves using a function as a parameter or other value.

Make the cell drawing function a parameter of `grid()`.

``````function setup() {
createCanvas(windowWidth, windowHeight);
}

function draw() {
background(200);
grid(5, 6, circles);

translate(width / 2, height / 2);
grid(3, 4, circles);
}

function grid(rows, columns, drawer) {
for (let row = 0; row < rows; row++) {
for (let column = 0; column < columns; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;

drawer(x, y, row, column);
}
}
}``````  Now different calls to `grid()` can draw different cells.

``````function setup() {
createCanvas(windowWidth, windowHeight);
}

function draw() {
background(200);
grid(5, 6, circles);

translate(width / 2, height / 2);
grid(3, 4, decoratedSquare);
}

function grid(rows, columns, drawer) {
for (let row = 0; row < rows; row++) {
for (let column = 0; column < columns; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;

drawer(x, y, row, column);
}
}
}``````  # Appendix II: Why `push` and `pop`

``````function draw() {
background(100);

for (let i = 0; i < 30; i++) {
let row = i % 5;
let column = floor(i / 5);

let x = 30 + 50 * column;
let y = 40 + 50 * row;

myShape(x, y, row, column, i);
}
}

function myShape(x, y, row, column, i) {
translate(x, y);

let size = map(row - column, 0, 10, 30, 40);
circle(0, 0, size / 2);
square(0, 0, size);
circle(size, y, size / 2);
circle(0, size, size / 2);
circle(size, size, size / 2);
}``````  Draw just the first shape

``````function draw() {
background(100);

for (let i = 0; i < 30; i++) {
let row = i % 5;
let column = floor(i / 5);

let x = 30 + 50 * column;
let y = 40 + 50 * row;

myShape(x, y, row, column, i);
break;
}
}

function myShape(x, y, row, column, i) {
translate(x, y);

let size = map(row - column, 0, 10, 30, 40);
circle(0, 0, size / 2);
square(0, 0, size);
circle(size, 0, size / 2);
circle(0, size, size / 2);
circle(size, size, size / 2);
}``````  Draw just the fourth shape

``````function draw() {
background(100);

for (let i = 0; i < 30; i++) {
let row = i % 5;
let column = floor(i / 5);

let x = 30 + 50 * column;
let y = 40 + 50 * row;

if (i === 3) {
myShape(x, y, row, column, i);
}
}
}

function myShape(x, y, row, column, i) {
translate(x, y);

let size = map(row - column, 0, 10, 30, 40);
circle(0, 0, size / 2);
square(0, 0, size);
circle(size, 0, size / 2);
circle(0, size, size / 2);
circle(size, size, size / 2);
}``````  Fixed: add `push()` and `pop()`

``````function draw() {
background(100);

for (let i = 0; i < 30; i++) {
let row = i % 5;
let column = floor(i / 5);

let x = 30 + 50 * column;
let y = 40 + 50 * row;

myShape(x, y, row, column, i);
}
}

function myShape(x, y, row, column, i) {
push();
translate(x, y);

let size = map(row - column, 0, 10, 30, 40);
circle(0, 0, size / 2);
square(0, 0, size);
circle(size, 0, size / 2);
circle(0, size, size / 2);
circle(size, size, size / 2);
pop();
}``````  