let rows = 5;
let columns = 6;
function setup() {
createCanvas(windowWidth, windowHeight);
}
function draw() {
background(200);
for (let row = 0; row < rows; row++) {
for (let column = 0; column < columns; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;
square(x, y, 30);
}
}
}

Note: From here on, the definitions of rows, columns, and setup() are not shown. Each of the following code samples assumes that the sketch also contains a setup() function, and definitions of rows and columns:
let rows = 5;
let columns = 6;
function setup() {
createCanvas(windowWidth, windowHeight);
}
function draw() {
background(200);
for (let row = 0; row < rows; row++) {
for (let column = 0; column < columns; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;
let size = 30;
if (row === 3) {
if (column === 2) {
size = 50;
}
}
square(x, y, size);
}
}
}

The nested if (the if within another if) above can be replaced by "and" (&&).
function draw() {
background(200);
for (let row = 0; row < rows; row++) {
for (let column = 0; column < columns; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;
let size = 30;
if (row === 3 && column === 2) {
size = 50;
}
square(x, y, size);
}
}
}
Replace a cell by a circle. Rectangle positions are specified as the upper left corner, and circle positions are specified as the center, so this looks bad.
function draw() {
background(200);
for (let row = 0; row < rows; row++) {
for (let column = 0; column < columns; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;
let size = 30;
if (row === 3 && column === 2) {
circle(x, y, size);
} else {
square(x, y, size);
}
}
}
}

rectMode() changes the behavior of square() (and rect()) to match circle(), so that it is easier to use square() and circle() (and rect() and ellipse()) interchangeably.
Note: This is a general principle. If there are two things – in this case functions — that you want to use interchangeably, see if there’s a way to make them more alike. In this case, there is a setting that does this. If they things that you created (such as functions you wrote), you have total control over this. Otherwise, you can create a shim or wrapper around one of the things.
function draw() {
background(200);
rectMode(CENTER);
for (let row = 0; row < rows; row++) {
for (let column = 0; column < columns; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;
let size = 30;
if (row === 3 && column === 2) {
circle(x, y, size);
} else {
square(x, y, size);
}
}
}
}

We can look at any combination of and row and column, and functions that combine them, to decide what to draw in a cell.
function draw() {
background(200);
for (let row = 0; row < rows; row++) {
for (let column = 0; column < columns; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;
let size = 30;
if (row % 3 === 0) {
circle(x, y, size);
} else {
square(x, y, size);
}
}
}
}

function draw() {
background(200);
for (let row = 0; row < rows; row++) {
for (let column = 0; column < columns; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;
let size = 30;
if ((row * column) % 3 === 0) {
circle(x, y, size);
} else {
square(x, y, size);
}
}
}
}

Note: For the following code samples, the values of rows and columns have been changed to 20.
function draw() {
background(200);
for (let row = 0; row < rows; row++) {
for (let column = 0; column < columns; column++) {
let x = 30 + 50 * column;
let y = 40 + 50 * row;
let size = 30;
if ((row ** 2 + column ** 2) % 3 === 0) {
circle(x, y, size);
} else {
square(x, y, size);
}
}
}
}
