What's that?
[TRAIN WHISTLE]
The coding train is pulling into the station?
Yes, it is.
And it's bringing with it vectors and a Lévy flight.
So I'm going to, in this video--
oh, that sound effect ended.
Thank goodness.
That was very embarrassing.
In this video, I am going to expand
on my previous random walker example,
and I want to do two things.
One is, I want to bring in the concept of vectors.
So instead of having a separate x and y variable,
I want to have a variable that keeps that x and y together
as a vector.
And this is going to allow me to be a bit more
flexible about how motion works and kind
of play with the quality of the random walk a bit more.
I am also going to add something called a Lévy flight.
So there are so many ways you can vary the probability
and quality of a random walker.
And I hope that maybe some of you
have already done that and shared some of your variations
with me.
A know concept, a known technique,
is something called the Lévy flight.
And what the Lévy flight is modeled after,
so something that actually happens in nature.
Sharks and other large sea animals
and maybe birds of prey and different hunting--
what a lot of these animals do looking for food
is they'll look around to try to find something,
to hunt their prey.
If there's nothing there, then they'll take a really long step
and go somewhere else, and then make smaller steps
to look around.
So unlike the current random walk that I have,
this random walk can only ever move one pixel.
And it never suddenly jumps.
But what if this random walk, looking around for berries,
because it likes berries, but there's no berries over here.
Let's go all the way down here and now look around
and see if we can find berries.
And then come all the way over here, and now look around.
Wouldn't it be great if it would just draw as I did that?
I'm going to get that working some day.
And go around and go here, and go up here.
So this is one of the things that I want to add to this.
How do I vary the probability of the step size
to forage for berries?
What's your favorite berry?
Mine is blueberry.
Although I have this acid thing, and I'm told that I'm not
supposed to have blueberries.
Melon is good.
This is off topic.
OK, so let's look at-- first, we're
going to make this easier.
Let's add vectors to this.
OK, so what is a vector?
Now first of all, if you want to do a deeper dive into vectors,
I'll link to my playlist from the Nature of Code
playlist, all about vectors that you can look at.
And also the Kadenze course that I mentioned,
I'll link to it here, which is an online course, not
on YouTube, but has videos for free.
I look at vectors in JavaScript, which
is probably more relevant to this particular video.
My ones on YouTube are using processing in Java.
But anyway, what is a vector?
So I mentioned that the random walker has an x, y position.
And I probably shouldn't draw this arrow here,
because the thing that I'm going to use to demonstrate vectors
is an arrow.
So this right here is an x, y point.
So a vector is an entity that has
both a magnitude and direction.
So typically, that is drawn as an arrow.
Its direction, you can think of it
as the sort of angle of orientation.
I'm just thinking about vectors in 2D.
The idea of a vector is actually just
essentially a list of values in some dimensional space.
And this is a big thing in machine learning
and all sorts of-- but I'm thinking of a very simple idea,
of just a vector in two dimensions.
It has a direction, its angle.
And it has a magnitude, the length of the arrow.
This is the idea of a vector.
It's this arrow that's long or short.
The components of it are a displacement along the x-axis
and a displacement along the y-axis.
So the way that you could think about this point as an x, y
is actually a vector that points from the origin to that point.
So if you need it to travel from 0, 0 to where that spot is,
you would need to go a certain amount of y
and a certain amount of x, and you would be there.
And the vector positions you there.
Now, a vector doesn't have a particular location.
A vector is just this entity.
So we could also consider each step to be a vector.
So before, when we had the random walk,
the random walk could only ever move up, right, down, left.
And this is sort of a formal definition
of the classic random walk.
But I'm going to do a vector random walk, meaning,
it could go one unit in any given direction.
And then that vector, its length could be variable.
So what is the probability of it moving one
unit versus moving many units?
And this is how we're going to get that Lévy flight.
So now I'm going to do my vector random
walk back to the computer.
This is a random walk.
OK, here I am.
OK, so let's go to the code and start implementing
some of this stuff.
So basically, what I want to do is,
I want to get rid of my x and y.
And I instead want to say, I'm going to call it
P-O-S, pos, for position.
And instead of setting x equal to 200 and y equal to 200,
I'm going to say, pos equals createVector 200, 200.
So this function in p5, createVector,
just makes a vector object.
A vector object is part of the p5 library.
And now I have this vector object
in pos, which has an x and a y.
And just so we can see it, I can say, console.log, pos.
So we can take a look at that, what that object looks
like in the console.
I can't type.
OK, now what I want to do is, instead
of drawing the point at x and y, I
want to draw the point at pos.
But the point function and the ellipse function and the line
function, they always expect the separate x and y values.
And I can access those by saying dot x and dot y.
So a vector is an object.
And objects in JavaScript have properties that you can access
by saying dot the thing--
pos dot, pos dot, pos dot song?
No, maybe?
Maybe, not really.
OK, so then I could also just say, hey, pos.x equals pos.x
plus 1, pos.x.
Oh, I'm going to do this in a faster way.
I kind of want this video to speed up
right now. pos.x, pos.y, pos.y, pos.y, pos.y, and now
I should have exactly the same program.
If I refresh, we can see it's doing exactly the same thing.
The random walker is moving around randomly.
And you can see here, here's my object.
My object is a p5 vector with an x and y.
By the way, it has a z.
So at some point, I'm going to come back and look
at doing a random walk in 3D.
The vector object in p5, also in processing,
has a z built into it.
But I'm just ignoring that fact right now.
And if I type in the console here pos again,
I can see these are its current values.
That's where it is right now, 178 and 214.
OK, so that's pretty good.
Now actually, though, I'm going to do something.
Here, I'm saying, there's only four options--
1, 2, 3, or 4.
0, 1, 2, or 3, move to the right, move to the left,
move up, move down.
I'm going to just radically change this completely.
I'm going to just take all this code out.
And what I'm going to do is I'm going to say, var step equals.
And what I want right now is a vector that has a length of 1
and points in any given direction.
And there's actually a function in p5
that will give me a vector like that already.
It would be interesting to discuss how you calculate
a random vector using just the random function,
but I don't need to.
Because I could say p5.Vector.random2D.
This is a little bit of a weird syntax here.
So why wouldn't I just say-- you could sort of say,
why isn't it just something like this, something like that?
Why isn't there just a global function random 2D
vector that gives me--
there's a global function create vector, right, create vector.
Why isn't there a create random 2D vector?
Well, there could be one.
In p5, the library could be implemented that way.
But to be honest, there's a bunch
of functions associated with vectors
that aren't so commonly used.
And they would really pollute, in many ways,
the simple p5 reference that has the core functionality.
So some of the functions that are associated with vectors
are actually inside of the sort of namespace, so to speak,
of the p5 vector object.
And you want to go to the p5 vector reference page, which
I'll link to in this video, to find
the documentation for this.
So to make a 2D vector, I've got to say p5.Vector.random2D.
And then guess what?
Now, what I want to do is say pos equals pos plus step.
Because what I want to say is, have a random step,
and then take a step every frame.
Take a step, random step, take a step every frame.
So this is my pos.
Add step to it.
This is my pos.
Add step to it.
But let's see what happens when I run this.
Nothing.
So JavaScript doesn't even give me an error message.
It just like, eh, uh, meh, uh.
So the reason why this doesn't work
is, JavaScript doesn't know what to do
with this plus and these values.
It knows how to do 2 plus 3.
That's 5.
10 plus 7 is 17.
I could keep going.
I could do addition.
I'm very proud of myself.
It also knows how to do plus with strings.
Rain plus bow is rainbow.
But it doesn't know how to do plus with vectors.
And some programming environments allow you
to overload-- the term is overload--
overload an operator and tell the programming environment
how to do it, with a plus sign, how it works.
But JavaScript doesn't have that--
there's ways around that-- but so easily.
So the way that I need to add a step to pos
is by looking at the p5 vector documentation.
And you'll notice there's a function called add.
So I could just say, pos.add step.
So once I say, this is a function
add that's part of the vector library,
I want to add the step vector to pos.
And now I'm going to hit Refresh, and we can see,
there we go.
Now, this is actually doing something quite different
than the previous video, because it's using floating point math.
And if I look at where the pos is right now,
you can see that it's at this number.
Now, one thing to note is that there's no, like, 213.84 pixel.
So when you say to draw it that number,
the browser or the operating system
is going to sort of figure out what to do.
Sometimes it just takes off the decimal place.
Sometimes it does some kind of what's
called subpixel rendering by kind
of using some alpha values to make like the illusion of it
in between pixels.
But we don't really need to worry about that too much.
You can see the quality of what we're getting
is essentially the same.
And now what I want to do is add the idea of a Lévy flight
to it.
So at some point, I would love to discuss a variety of ways
that we could control the probability of the step size.
Right now, ask yourself, what is the step size?
What is the step size?
You could pause the video to try to answer it.
The step size right now, which I mentioned a few times,
is actually 1.
So random 2D gives you, by definition,
what's called a unit vector, meaning
the length of that vector is 1.
But I could always change that length.
I could say, step.multiply by 5.
That takes the vector and scales it up times 5,
makes it five times as long.
And if I do that, you'll see--
whoa, did I not hit Save?
I did not hit Save.
Now you'll see, look what's happening there.
Oh, I've definitely got something
I've got to fix with this, I just noticed.
You can see that the step size is bigger
and the dots are further apart.
So incidentally, let's fix this issue right now.
I want to see a line from one spot to another
now that the steps are so big.
When it was only 1, the points would always
appear next to each other.
So to do that, I want a variable called previous.
And I'm going to say, previous equals pos.copy.
So this is kind of an interesting thing.
Because these are objects, the vector object
has built into itself--
and all objects have this-- a function called copy,
which creates a copy of it.
I don't want to say previous equals pos.
Because that way, if I change pos, previous changes,
they're actually pointing to the same data.
I want to make a copy.
So I want pos and previous to both
be a copy at the same spot.
And then what I want to do is draw a line between pos.x,
pos.y, and previous dot x, previous dot y.
Then, before I change the step, before I add step to pos,
once again, I want to say, previous equals pos.copy.
Now, this is actually kind of a bad idea.
It probably doesn't matter.
But I'm sort of unnecessarily creating new objects
over and over again.
So in this case, I think what I actually want to do is say,
previous dot set pos.
I think what that will do is just
say, set the values of previous to pause.
The reason why I couldn't do that up here
is because previous didn't exist yet.
So copy makes a new vector.
And the set function just takes an existing vector
and kind of copies the values over into it.
I think this will work.
So let's see now what we get.
We can see now it's connected with a line.
I guess I have an alpha in here that I didn't notice.
Let's take that out.
So you can see it's connected with a line.
And I could just change the step size now to 25.
And we could see, look, a random walk
is making really big steps now, 25 steps.
And then I could say, hey, what if I
make this a random value, a random step between 1 and 25.
Now, what you'll see is the step size is actually random.
So in order to complete the Lévy flight, what I need to do,
I need to have a probability of--
I need to have it be most likely that it's
going to take a small step, but every once in a while
take a big step.
And I'm going to do that in a kind of quick and dirty way,
which is just to say, let me pick a random number,
var r equals random 100.
You don't have to use a range from 0 to 100,
but this is a nice way to implement probability
in your code.
What if I want there to be a 5% chance of something happening?
Well, if I pick a number between 0 and 100,
that number is going to be less than 5 5% of the time.
I could have done this by saying, random 1,
and say, 0.05.
But just for readability right now, I'm
going to say random 100.
So let's just say there's a 5% chance of taking
a step that is actually sum that is actually 25 pixels.
So it's always going to make a vector that is one step.
And this, by the way, is making a new vector every frame,
but big deal.
That's a unit vector.
But 5% of the time, it's going to go 25.
So let's look at this.
And we can see we've now got this lead of like-- now 5%
is actually kind of often, you can see.
And 25 pixels is maybe not that long.
So maybe what I'm to do is actually
make that step randomly between 25 or 100,
and I'm actually going to make it just 1% of the time.
And so now we're going to see--
and maybe what I actually want to do is always
make the step size--
and by the way, there's a function
called setMag, set magnitude.
Right now, because its unit vector is 1,
if I multiply by 10, I get it's magnitude of 10,
because 1 times 10 is 10.
But if it's magnitude was like 15, and then I wanted to be 10,
I would have to divide it by 15 and then multiply it by 10.
So there's actually a function called setMag,
which is set the magnitude, which I could do.
I'm going to just set it 2, so its native sizes
are a little bit bigger.
And now you can see we've got the Lévy flight.
So this is one variation.
What kind of ideas could you have,
in terms of color and design or adding a narrative to this
that you might explore, or changing the probabilities?
Now, oh, there we go.
Oh, there we go.
So now we can see these large steps.
And so explore this.
Play with it.
The code from this video will be linked in the description.
If you make something with it, share it
with me on Twitter @shiffman.
Or share it in the comments.
And I try to at least read and go through all the comments.
Generally once a day, I'm kind of checking them and reading
them and enjoying them.
So thanks for tuning in to this second random walk Lévy flight
video.
[TRAIN WHISTLE]
[MUSIC PLAYING]