Lists
A loop repeats the work; a list says what to work on. One box holding many values, reached by number — so a handful of lines can draw a whole swarm, and a click can make it bigger.
1A List of Numbers
One box that holds several values instead of one, and a number in square brackets to reach any of them. No loops yet — every shape written out longhand, so the only new thing on the page is the list itself.
Lesson — read before you start
var sizes = [120, 40, 80];
Square brackets round the lot, commas between the items. That is one variable called sizes, and it is holding three numbers.
To get at one of them you say which one you want, in square brackets:
sizes[0]
and that is the first number, 120. The next one is sizes[1], which is 40, and the last is sizes[2], which is 80.
The thing to make peace with early is that the counting starts at 0. The first item is number 0, the second is number 1, the third is number 2. So a list of three items has a last item numbered 2, and there is no sizes[3] — asking for it gets you nothing at all, and the shape you were drawing quietly disappears with no error to tell you why.
sizes[0] behaves exactly like a number wherever you put it. You can draw with it:
circle(100, 200, sizes[0]);
You can do sums with it. You can read the same item twice. Nothing about it is special except where the value came from.
Why bother, when three ordinary variables would do the same job? Because the three numbers belong together. They are three of the same kind of thing, and keeping them in one box means the sketch can talk about all of them at once — which is what the rest of this course is about.
One habit worth starting now: name a list for what it holds, in the plural. sizes, heights, places. It reads properly when you index it, because sizes[1] really is one of the sizes.
There are no loops in this topic. Every shape gets its own line and its own number, written out longhand, and by the last challenge that will be annoying. That is the point, and the next topic is the answer to it.
2The Counter Picks the Item
A loop counts and a list picks, and sizes[i] is where they meet. One line now does what twelve did in the last topic, and the counter is quietly doing two jobs at once.
Lesson — read before you start
for (var i = 0; i < 3; i = i + 1) {
circle(70 + i * 130, 200, sizes[i]);
}
Look at where i turns up in that line. On the left it is doing arithmetic — 70, then 200, then 330, spacing the circles out. On the right it is inside square brackets, choosing which item of the list to use. Same counter, two completely different jobs, and it is worth being able to point at each of them.
The second job is the new one. Every time round the loop, i is a different number, so sizes[i] is a different item. Turn 0 draws sizes[0]. Turn 1 draws sizes[1]. Turn 2 draws sizes[2]. Three lines of Topic 1, written once.
The counting lines up because both start at 0. That is the real reason a list counts from 0 rather than 1 — a loop that starts at 0 and an index that starts at 0 fit together with no adjusting.
Two things to watch, and you will meet both.
The loop and the list are separate. Nothing keeps them in step. A list of six with a loop that stops at 3 draws half the picture, and a loop that stops at 8 asks for items that were never there. That second one is the quiet one: there is no error, no red line, nothing in the panel. The shape just does not appear, because there was nothing to draw it from.
Anything can go in the square brackets, as long as it works out to a number. i is the usual one, but 3 - i walks the list backwards, and i + 1 looks one ahead. Whatever is in there is worked out first, then used as the item number.
For now the number the loop stops at is one you count yourself and type in. That is a nuisance, and it is what Topic 5 is about.
3Two Lists, One Shape
A place is two numbers, so a shape that gets both of them from lists can go anywhere at all. Parallel lists, read at the same item number — the first pictures in this course that no sum could produce.
Lesson — read before you start
Give a shape both of its numbers from lists and that stops being true.
var xs = [50, 200, 350];
var ys = [300, 100, 250];
for (var i = 0; i < 3; i = i + 1) {
circle(xs[i], ys[i], 70);
}
Turn 0 draws a circle at 50 across and 300 down. Turn 1 draws one at 200 across and 100 down. Turn 2 at 350 and 250. Three circles, nowhere near a row, and no arithmetic anywhere in the picture — because the author simply said where each one goes.
The two lists are working as a pair. xs[1] and ys[1] belong together; they are the two halves of the same point. Lists used this way are called parallel lists, and the word is worth having because it names a promise: item number 2 in this list and item number 2 in that one are about the same thing.
Nothing enforces that promise. It is a habit, not a rule. If you add an across and forget to add a down, the lists stop being in step and the shape you were expecting quietly does not appear — the same silence as asking past the end, for the same reason. Whenever you edit one of a pair, look at the other.
Two lists is not the limit. A third holding sizes, a fourth holding something else — all read at the same i, all lining up item by item.
One thing that catches people out with lines. Joining point i to point i + 1 draws a path, but the loop then has to stop one turn early: five points make four lines, not five, and asking for point 5 of a five-item list gets you nothing.
And a list does not have to hold numbers. Put quote marks round the values and it holds words, read at an item number exactly the same way.
4Lists of Anything
A list holds whatever a variable could hold. Colours, words, thicknesses, text sizes — read out at an item number exactly the way a coordinate was, and the pictures stop being one colour all over.
Lesson — read before you start
var colours = [RED, YELLOW, GREEN, BLUE];
That is a list of four colour names, and it works exactly like a list of four numbers. colours[0] is RED. colours[2] is GREEN. Hand one to shapeColour and the shape comes out that colour:
for (var i = 0; i < 4; i = i + 1) {
shapeColour(colours[i]);
square(20 + i * 95, 160, 80);
}
Four squares, four colours, one loop.
The order of the two lines in there matters, and it is the one thing in this topic that catches people. shapeColour sets the pen for everything drawn after it. Set the colour, then draw. Draw, then set the colour, and the shape comes out in whatever the pen was holding from last time round — which looks like the whole row being one colour behind.
The same goes for anything else a list can hold.
Words, with quote marks round them: var words = ["red", "green", "blue"] and then write(words[i], 60, 200).
Outline thicknesses: outlineThickness(thick[i]).
Text sizes: textSize(big[i]).
Outline colours, fills, both at once out of two different lists. None of it is new machinery. It is the same square brackets and the same counter, and the only thing that changed is what is sitting in the list.
One warning about colours in particular. A colour is checked exactly — it either is YELLOW or it is not, and there is no nearly. A width that is five out will still score most of its marks; a colour that is wrong scores none of them.
And notice what the loop is still doing at the end of every one of these. It stops at a number you counted off the list yourself. Add a colour and the loop does not know. That is the next topic.
5How Long Is It?
Until now the loop was told how far to go by a number somebody counted. sizes.length is the list answering for itself, so the loop fits whatever is in it — and a length turns out to be a useful number in its own right.
Lesson — read before you start
for (var i = 0; i < 5; i = i + 1) {
That 5 is a guess. It is right until somebody adds a colour to the list and forgets to come back and change it, and then it is quietly wrong — either the last shape stops appearing, or the loop asks for an item that is not there and, again, the shape stops appearing. Neither of those says anything in the error panel.
A list knows how long it is, and will tell you:
sizes.length
That is a number, the count of items in sizes. Note the shape of it: a dot, then the word, and no brackets. It is not something the list does, it is something the list is.
Put it where the guess was:
for (var i = 0; i < sizes.length; i = i + 1) {
and the loop fits the list. Add an item, and it draws one more. Take two away, and it draws two fewer. You never touch the loop again.
The counting-from-0 thing shows up here once more, and this is the form it usually bites in. A list of five has length 5, and its items are numbered 0 to 4. There is no item 5. So the last one is:
sizes[sizes.length - 1]
with the minus one. Leave it off and you are asking past the end.
The other half of this is that a length is just a number, and it can go anywhere a number goes. Divide the canvas by it to get a gap that always fits. Multiply by it to find out how wide the whole row will be. Halve it to draw only the first part. None of that is about stopping a loop at all.
The line along the bottom of the picture is showing you the length as the sketch sees it. Add an item and watch it go up.
And there is a bigger reason to stop hand-counting than tidiness. A loop that asks the list is ready for a list that changes while the sketch is running — which up to now has never happened. That is what Growing a List, two topics on, is about.
6Choosing from a List
A loop does the same thing to everything. An if inside it does not — so the tall bars can stand out, the ones outside the box can be left off, and the sketch can work out which item is the biggest.
Lesson — read before you start
An if inside the body is the way.
for (var i = 0; i < tall.length; i = i + 1) {
if (tall[i] > 180) {
shapeColour(RED);
} else {
shapeColour(GREY);
}
rectangle(20 + i * 64, 320 - tall[i], 48, tall[i]);
}
The question is asked afresh on every turn, about that turn's item. Six bars, six separate answers, and the tall ones come out red.
Two kinds of question are worth telling apart, because they pick out different things.
A question about the item — tall[i] > 180 — is about the value, so it picks out shapes by what they are. Move the values around in the list and the same bars stay red; they have just moved.
A question about the counter — i == 3, or i < sizes.length / 2 — is about the place, so it picks out shapes by where they are in the row. Move the values around and the same positions stay lit whatever is now in them.
An if with no else simply skips the turn. Nothing is drawn, no gap is left, the loop moves on. That is how you draw only some of a list.
A turn can look at more than its own item. The square brackets take a sum, so tall[i - 1] is the one before — which is how you ask whether the line is going up or down. Start that loop at 1, because item 0 has nothing behind it to compare with.
And a variable made before the loop lives through all of it. Set it to 0, add one inside the if, and by the end it is a count of how many passed. Or start it at 0 and let every item that beats it become the new value, and by the end it is the biggest. Neither of those is anything a single item knows — they are facts about the whole list, worked out one turn at a time.
7Growing a List
push puts one more value on the end while the sketch is running. In start it happens once; in a handler it happens when you click — so the list stops being something the author typed and becomes something you build.
Lesson — read before you start
sizes.push(140);
That puts 140 on the end of sizes. The list is one longer than it was, and sizes[sizes.length - 1] is the new value. It always goes on the end, never in the middle and never at the front, whatever the value is.
Notice the shape of it: a dot, the word, and round brackets with the value inside. .length was a thing the list is, and had no brackets. push is a thing the list does, and has them.
Where you put a push decides when the list grows.
In start, it happens once, before the first frame. The sketch draws the longer list from the very beginning and nothing appears to change.
In a handler, it happens when someone does something. That is the interesting one:
function whenMouseClicked(){
xs.push(mouseX);
ys.push(mouseY);
}
Click, and the point where you clicked goes on the end of the lists. everyFrame loops over them and draws one more circle than it did a moment ago. Click again and there is another. You are building the drawing rather than reading one out of the source.
Not in everyFrame, though. A push there happens twelve times a second and never stops.
Two things this rests on, both of which you already have.
A handler changes a variable rather than drawing — and pushing to a list is changing a variable, even though there is no equals sign anywhere in the line.
And the loop has to be asking the list how long it is. A loop that stops at a number somebody counted will keep drawing that many shapes for ever, and the pushed items will sit in the list unread with nothing anywhere to say so. That is what the last topic was for.
A list can start with nothing in it: var spots = []; is an empty list, its length is 0, and a loop over it runs no turns at all. Perfectly correct, and it draws nothing until the first click.
From challenge 7 on, the picture is live the moment the page loads, because there is real input in it. Click on it yourself and watch the row grow; nothing is marked until you press Run, and the graded run then replays a scripted set of clicks rather than yours.
The line along the bottom is showing you the length. Watch it climb.
One thing a list still cannot do after this topic: none of these pictures move on their own. Everything in them is decided the moment it is drawn. The next topic puts a value back INTO a list every frame, which is how a whole swarm of shapes each ends up remembering where it has got to.
8Lists that Move
A square bracket on the left of an equals sign writes into the list instead of reading from it. Give every shape its own place and its own speed, and a dozen things can move at a dozen different rates.
Lesson — read before you start
The new line is this one:
xs[i] = xs[i] + 5;
Every square bracket you have written so far has been a read. That one is on the left of an equals sign, so it is a write: take item i, add 5, and put the answer back where it came from. Next frame it reads the new value and adds 5 again, and the shape drifts across.
One list, and one speed for everybody. Two lists, and everybody gets their own:
for (var i = 0; i < xs.length; i = i + 1) {
xs[i] = xs[i] + speeds[i];
circle(xs[i], 60 + i * 80, 50);
}
Item 0 moves at speeds[0] and item 3 moves at speeds[3]. They start level and they do not stay level. That is a picture Course 3 could not draw at all, and Course 5 could only draw by making every shape identical.
A few things worth knowing.
A negative step goes the other way. A step of 0 stands still. A speed list can hold both, and the row splits.
Whatever a list can hold, it can be written back into. Sizes grow. Speeds themselves speed up, if you add to them each frame before you use them. The colours in these sketches never change, and the reason is simply that nothing ever writes to the colour list.
An if inside the loop asks about one item and writes the answer back into another list at the same number. That is a bounce: once xs[i] has gone past the wall, speeds[i] becomes minus itself, and only that shape turns round.
Set the colour inside the loop, immediately before the shape it belongs to. The pen carries over from one frame to the next as well as from one shape to the next, so a colour set at the bottom of everyFrame is still in the pen at the top of the following frame.
And solid shapes that grow in the same place turn into one blob. Rings do not, which is why the growing challenges here use noShapeColour with an outline.
The line along the bottom is the frame number. Step across it one frame at a time and watch the items pull apart.
That is the last new idea in the course. The next topic has none at all: whole lines go missing instead of numbers, and everything you have to write to fill them in is something on this page.
9Write the Lists Yourself
Whole lines are missing rather than numbers, and the comment above each gap is the only instruction. One line to begin with, five by the end, and the last five animate.
Lesson — read before you start
Each gap has a comment directly above it saying what the line has to do, and that comment is the only instruction there is. Read it, write the line underneath it, press Run.
The comments name the call and where its numbers go, like this:
// circle at xs[i] across, ys[i] down, 60 wide
so you never have to guess the order of the arguments. What you do have to supply is the shape of the line itself — which list, which item number, and what to do with the value once you have it.
Two kinds of line come up over and over, and it is worth being able to write both without thinking.
Reading: shapeColour(colours[i]), circle(xs[i], ys[i], 60). Take the item at the counter and use it.
Writing: xs[i] = xs[i] + speeds[i]. Take the item at the counter, work something out, put the answer back in the same place.
Some lines are not lines you can leave blank, so you will find those given to you with something wrong in them instead. A for header, a function header, an else, a var declaration — blanking any of those breaks the brackets and the sketch will not run at all, which teaches nothing. Where the loop header is the question, it is sitting there with the wrong stopping point in it.
The first fifteen are still pictures. From sixteen the frame readout comes back along the bottom, the sketches animate, and the lines you are writing are the ones that put a new value back into a list every frame.
Work down the comments in order. If a shape does not appear at all, the usual reasons are that the item number is past the end of its list, or that the line drawing it is inside the wrong pair of curly brackets.
10Code it yourself
An empty editor and a row of blocks above it, with a list and a push among them. No holes to fill and no lines to copy — the description says what the sketch draws, what goes in every list, and what a click does to it.
Lesson — read before you start
There is no starter here. The editor opens empty and a row of blocks sits above it. Click one and it drops the shape of the code in at the cursor, already indented, with the caret where you have to fill it in.
The Values row has the two list blocks:
var sizes = [40, 90, 140];
and
sizes.push(200);
The Structure row has everyFrame, for, if and else in it. Drawing and Style have the shapes and the colours. The two bits of list vocabulary that are not on a button are the ones that are not statements — sizes[0] and sizes.length — and both are a few keystrokes inside a line a button has already given you.
The description is the whole instruction. It tells you the background, every shape with its place and its size, every value that goes in a list, and what any input does. Every number you need is in it and nothing that is not, so read it as a list and work down.
Three things worth having in your head before you start.
Name a list in the plural for what it holds, and reach into it with the counter: sizes[i], places[i], colours[i]. Two lists read at the same i are two halves of the same thing.
Stop the loop with the list, not with a number you counted. i < sizes.length is right however long the list turns out to be, and it is the only version that still works after a push.
And a list is not just for drawing out of. Put a value back into it — xs[i] = xs[i] + 5 — and the shape remembers where it got to, which is what makes the moving ones move.
There is no readout along the bottom of these pictures. Turn the grid on if you want to check where a shape has actually landed. The two that react to the mouse are live from the moment they load, so try clicking on them before you press Run.