Loops and Grids
Students will leave the session with an understanding of loops as a form of automation and the ability to control the flow of programs with conditionals.
Class Agenda
Morning Sketching | 8:30 - 9am |
Presentations & Critique | 9 - 10am |
BREAK 30min | |
Read & Discussion | 10:30 - 11:30am |
Code Lecture | 11:30 - 12pm |
BREAK 30min | |
Workshop | 12:30 - 2pm |
Morning Sketch
Recreate one of Piet Mondrian's geometric paintings, such as Composition No. III.
Weekly Assignment
Create a grid/pattern of tiles using loops. Create functions as needed to abstract away some of the more complex visual logic.
Readings
- What is Parametric Design? by Robazzo
- On meta-design and algorithmic design systems by Rune Madsen
Discussion Questions
- What do we think of designing at the system level with multiple parameters and outcomes?
- Are there existing design tools that allow for quick iteration?
- Are rules and systems important for designers? In which ways might they be harmful or outdated and how might that affect the designer?
- Is a possible future of design tools very specialized?
- How might the ability to create specialized design tools change the profession?
Further Resources
- Generative Logo Design by Components.ai
- A Field Guide to Debugging by p5js.org
- Expressions, variables and loops by Allison Parrish
Code Lecture
Loops
Loops allow us to repeatedly run an operation. For example let's manually create a line of 4 columns:
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
rect(0, 0, 100, height);
rect(100, 0, 100, height);
rect(200, 0, 100, height);
rect(300, 0, 100, height);
}
This first example achieves the goal but at the same time is repetitive and doesn't make our code and logic easy to maintain. If you wanted to change the size of the column you would have to update it in multiple places. Let's swap in a variable to see how that clean up our logic.
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
var columnWidth = 100;
rect(0, 0, columnWidth, height);
rect(columnWidth, 0, columnWidth, height);
rect(columnWidth * 2, 0, columnWidth, height);
rect(columnWidth * 3, 0, columnWidth, height);
}
This example is better and makes our program more resilient but it is still repetitive as we have multiple copies of the column logic. We can further automate this using a loop. The purpose of a loop is that they allow us to repeat a task. One example of a loop is a for loop and the syntax for it is:
for ([initialization]; [condition]; [final - expression]) {
// logic
}
Initialization is where you create the variable that will track the current state of the loop. Condition is a statement that is evaluated at the start of each loop. The loop continues to run while this statement is true. The final expression is run at the end of every loop and is usually where you update the state of the variable created during initialization. Let's create a simple loop that runs 10 times.
for (var index = 0; index < 10; index += 1) {
// logic
}
- Initialization - Create a variable named
index
with a value of 0 - Condition - For every loop check if
index
is less than 10 - Final Expression - Increase the value of
index
by 1
So this example loop will run 10 times. We can verify this by outputting the value of index during each loop.
for (var index = 0; index < 10; index += 1) {
// You can use the + operator to join Strings together.
console.log("index " + index);
}
Some things to note. In our example above index is initialized with a value of 0 because in coding we usually start loops at 0 instead of 1. A common use case for a loop is to iterate over a list of items and lists in a lot of programming languages have their first item at the index of 0 instead of 1. We will cover this more once we get to the lecture on arrays. You can start your loop at whatever value you would like and update it however you would like as well.
for (var index = 0; index < 10; index += 2) {
console.log("increment by 2: " + index);
}
for (var index = 10; index > 0; index -= 1) {
console.log("decrease index: " + index);
}
Revisiting our example with the rectangles we can now use the value of index
to compute the square's position.
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
var columnWidth = 100;
for (var index = 0; index < 4; index += 1) {
// x position increases by columnWidth each loop
var x = columnWidth * index;
rect(x, 0, columnWidth, height);
}
}
Conditionals
Conditionals allow us to introduce control and conditions to our program. The first conditional we will look at is an if statement. The syntax for it is:
if (condition) {
// the steps to perform
}
The following code is a if statement that will output our message as long as number is less than 1.
var number = 0;
if (number < 1) {
console.log("this number is less than 1");
}
You can start to bridge your knowledge to branch out and handle different use cases. Another type of conditional is an if...else statement. The syntax for it is:
if (condition) {
// logic
} else {
// alternative logic
}
With this we can update our code to always output something.
var number = 0;
if (number < 1) {
console.log("this number is less than 1");
} else {
console.log("this number is greater than 1");
}
But this logic doesn't behave as expected when number
is given the value of 1. We can further cover this use case by adding an else if statement.
if (condition) {
// logic
} else if (second_condition) {
// logic
} else {
// logic
}
With this our example can correctly be updated to cover all use case.
var number = 0;
if (number < 1) {
console.log("this number is less than 1");
} else if (number > 1) {
console.log("this number is greater than 1");
} else {
console.log("this number is equal to 1");
}
Booleans
Boolean is a javascript data type that represents true
or false
. When you use conditionals you are using a boolean value and similar to strings and numbers they can be assigned to variables and reused throughout your code.
var number = 0;
var isNumberGreaterThanOne = number < 1;
var isNumberLessThanOne = number > 1;
if (isNumberGreaterThanOne) {
console.log("this number is less than 1");
} else if (isNumberLessThanOne) {
console.log("this number is greater than 1");
} else {
console.log("this number is equal to 1");
}
// you can use the value of the condition elsewhere...
More Operators
Now that we are starting to add control logic to our programs let's introduce more operators as ways to write conditions.
Relational Operation | operator |
Less than operator. | < |
Greater than operator. | > |
Less than or equal operator. | <= |
> Greater than or equal operator. | >= |
Equality Operation | operator |
Strict equality operator. | === |
Strict inequality operator. | !== |
Other Operators | operator |
Remainder Operator | % |
Relational Operators allow us to check the relation between two values, for example if one is bigger than the other. Equality Operators allow us to check if two values are equal or not. The Remainder Operator returns the leftover value when one number is divided by another. This comes in handy when we need to add rhythm to our sketches. Now, let's revisit our example with the columns:
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
var columnWidth = 100;
for (var index = 0; index < 4; index += 1) {
// x position increases by columnWidth each loop
var x = columnWidth * index;
if (index % 2 === 0) {
push();
fill("black");
rect(x, 0, columnWidth, height);
pop();
} else {
rect(x, 0, columnWidth, height);
}
}
}
Grid (Nested Loops)
We can nest loops to create more complex calculations, like for example a grid. So far we've been creating a column along the width of our canvas. With nesting we can create a loop for the height of the canvas and create a grid.
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
var cellHeight = 100;
var cellWidth = 100;
for (var rowIndex = 0; rowIndex < 4; rowIndex += 1) {
for (var columnIndex = 0; columnIndex < 4; columnIndex += 1) {
// x position increases by cellWidth each loop
var x = cellWidth * columnIndex;
// y position increases by cellHeight each loop
var y = cellHeight * rowIndex;
rect(x, y, cellWidth, cellHeight);
}
}
}
Patterns
Knowing the cell's place in a grid means we can compose shapes to make different patterns and variations.
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
var cellHeight = 100;
var cellWidth = 100;
var circleSize = 90;
for (var rowIndex = 0; rowIndex < 4; rowIndex += 1) {
for (var columnIndex = 0; columnIndex < 4; columnIndex += 1) {
var x = cellWidth * columnIndex;
var y = cellHeight * rowIndex;
var isAlternatingRow = rowIndex % 2 === 0;
rect(x, y, cellWidth, cellHeight);
// alternate between these two sets of logic every other row
if (isAlternatingRow) {
push();
fill("pink");
ellipse(x + cellWidth / 2, y + cellHeight / 2, circleSize, circleSize);
pop();
} else {
push();
fill("papayawhip");
ellipse(x + cellWidth / 2, y + cellHeight / 2, circleSize, circleSize);
pop();
}
}
}
}