(rings bell)
(blows flute)
Hello, and welcome to a 2018
holiday coding challenge, snowflakes!
So, I was perusing the internet last night,
and I found this page, I think my search term was like,
Brownian motion snowflake fractal,
and I found this page, it's from a website
called Code Golf that has a lot of different
coding challenges on it.
I think the idea of the challenge is to write
the shortest amount of code to create this kind of effect.
I am not going to attempt that,
I'm probably going to write the longest amount of code
to make this kind of effect, but my goal
is to try to make a snowflake pattern like this.
Now, if you read over this webpage, and there's a
few diff, this is an example that was made in Mathematica,
which I don't understand at all.
But the algorithm that's described here is, you can,
here that it's a Brownian tree on an integer lattice,
that sounds so fancy!
The idea is, if you just think about a number line,
or the x-axis of any coordinate system,
and I were to start with a point back here,
and I were just to allow that point
to, like, randomly move around,
do a random walk, so to speak,
random walk,
and at some point I would have to tell it to stop.
So maybe, maybe what I would do,
is I would tell it to stop if it got to, like, over here.
(laughter)
The path, maybe this is the 0, 0 coordinate.
If it got to here it should stop.
And then I'm going to start another one.
And I'm going to let that one do a random walk.
Now, it's going to stop also if it gets to
either past here, or if it touches another previous,
I'll call these particles.
And this, by the way, is basically an algorithm called
Diffusion Limited Aggregation.
And this is actually something that
I have done previously in a coding challenge.
I'll pull up that page right here.
You can, I'm mostly going to implement the exact same thing.
But you can see you'll get this branching pattern.
So here, the dot, there's one dot
that starts at the center
and everything kind of branches out from there.
And we could use a recursive tree structure.
There's all sorts of kinds of way
we could create this branching pattern.
But what's interesting about this,
how can we make a snowflake?
Well, I don't really know.
I'm not, no expert on the actual science of snowflakes,
but if you've looked at most snowflakes' designs,
they are in a hexagonal pattern.
We can think of that as a bunch of,
like, triangular slices.
Slices of a pizza pie right here, right.
So if I were to kind of constrain
this branching to within this sort of
half of this slice, like right here,
then what I could do is I could take this,
I could reflect it on the other side,
which would give it some symmetry,
and then rotate it also around six times,
and I think, I'm pretty sure, that's what that is happening
in that animation that I showed in the beginning.
So this is what I'm going to attempt to do.
I'm sure, I'm not sure, but I expect
there are lots of creative possibilities
with color, and improving the algorithm,
and size, and rendering that you could do
from watching this.
So my hope is that we will now be filled
with a world of code made snowflakes.
But let's start this and see.
It's similar to probably also to, like,
what you would do to make a kaleidoscope program I think.
So let's start trying to do this.
I'm going to do this in Processing,
which is a Java based programming environment.
This is, by the way, being recorded during a fundraiser.
You can go to processingfoundation.org/support
to make a donation to the non-profit Processing.
And I will also release a JavaScript version
in p5.js that you can also use
to make this thing happen in the browser.
Alright, so the first thing that I want to do
is I just want to make a particle.
Oh I guess I need to have a class.
(laughter)
So let's make a class called particle.
Do I dare use p-vectors?
Let's try to be simple for a little bit
here for a second.
Let's start without p-vectors
and let's just make the particle have
an x and a y,
and I'm going to say the particle
is going to start at some other x and y,
so this is a, this is a class
from which I'm going to make particle objects,
and this is the class's constructor
that is going to receive an x and a y
and create the particle there.
I probably actually don't,
I could've just used a single vector actually,
but that's fine.
Let's make a particle class.
And then what I'm going to do is
I'm going to write a function called,
like, update
and I'm going to say x equals,
so I'm going to do a really simple random walk,
which it's all, I'm going to make the particle,
I'm going to start it this way.
I probably want to, like, start the particle
somewhere around here,
and then have it randomly walk in this direction
to stay within the slice,
but just for simplicity's sake,
let's start it right here right now
and have it randomly go this way.
I'm going to say x equals,
x minus equals one,
y plus equals some random number
between negative one and one, alright.
So let's do that.
And then let's make a particle.
I'm going to call it current.
And let's say size 600 600 for the window,
and I'm going to make a new particle,
which is going to start at 600 comma zero,
and I'm going to say background zero.
Current dot update.
And then let's also write a function like show.
So, I'm going to write a function called show
and let's just draw this as, it'll be white
with a white outline
and this should probably have a size too.
Let's give it a radius
and then I can just set that
always to be, like, three.
I don't know, I'm making this up.
Ellipse, x comma y
r times two
because the radius is, the diameter is the radius times two.
Alright, so now if I were to say,
oh, this should be good.
Oh there it is.
There it is, it's wandering around up there.
Okay, so one thing I want to do
is I really, this is going to work much better,
if everything can be relative to the center.
So I'm going to translate zero zero to the center.
Let's do that.
Translate width divided by two,
height divided by two.
And then the particle should actually start
at width divided by two
'cause it's that far out.
It could start further out, but,
and now we can see, there it is.
There's my particle.
Go, go particle.
You can do it.
You can make it to the center.
Okay, it's just going to keep going,
so there's, I need some way of telling it to stop.
(laughter)
So, let's say if current dot finished,
then what I want is I want to have a big array,
I mean, I could just not erase the,
I could render it to, like,
a separate graphics object or something,
but let's, this'll be the less efficient way,
but let's make an array list
that is full of particles.
Let's call this the snowflake.
Snowflake equals new, what was I saying,
array list.
New array list of particles,
and then if it's finished
I'm going to say snowflake dot add
the current particle,
and then I should remake the current particle again,
like I should make a new current particle.
And then I also should for every particle p in snowflake,
I should show them all.
So the idea here is that I have this particle wandering.
As soon as it's done it gets added to the list
and a new one starts wandering.
So I need to implement this finished function.
As you can see this read squiggly is like
I don't know what that is.
What does it mean for a particle to be finished?
And I can say boolean finished
'cause I want this function to return a boolean variable.
I mean, yeah, a boolean value, true or false.
Return x is less than zero.
So it's finished when x is less than zero.
Obviously I'm going to have to get
more sophisticated than that,
but that will be a good start.
So let's see here.
Go particle, go.
Go particle, go, stop.
Go particle, go.
Go particle, stop.
Okay, so that's good.
This is kind of working.
I actually, I really kind of want to reflect,
do the kaleidoscope thing now so we always see that.
Oh that'll be so fun.
So the particle is finished
if also, if it's, if it's past zero
or if intersects another particle.
So, I guess I could say, if current is finished
or current intersects snowflake, the existing.
So now I need to write also
another function called boolean intersects
and does it intersect,
the snowflake is just an array list, right.
(groans)
A particular snowflake.
And then let's just put a return false here for a second,
make sure this is still working.
So it's still working, it's never going to stop.
But now it will also, if, okay,
I'm thinking, I'm thinking,
it's so hard to talk and code.
If it intersects itself, like,
I have to just check every other snowflake against it
and current is not currently in the snowflake array
so I don't have to check it against itself.
So, I'm going to assume a result,
I'm going to assume it's not intersecting anything.
Then I'm going to check everything
for particle s in snowflake
if, and then I just need to get the distance
between s x, s y, and this x, and this dot y.
By the way, I should mention I have this thing
(upbeat music)
where I always forget the this dot, this dot,
but actually in Java, the this dot is assumed,
but in this case I kind of felt like
I wanted to put it in there,
'cause I want the distance between s dot x
and this dot x, this dot y,
but I don't actually need it.
So that's what I'm doing.
And then I'mma say if the distance is less than
the radius times two also,
then result equals true.
And I can also break out of the list, the loop.
Like I don't need to keep checking.
I can say break and then return result.
So now, this should get me,
that it's going to stop if it,
if it intersects another dot or gets past zero.
Come on, oh!
So exciting, it worked.
Go, go, go, go, go, this is like so slow.
So this would actually be,
it's sort of interesting to think about
whether we want to animate this or not.
Great, so this is working.
What I want to do right now, let's,
let's do the crazy thing I want to do,
which is kaleidoscope it.
So I want to actually now while this is happening,
I want to reflect it along this axis
and then also rotate it around six times.
I think six is the right number.
I'm not really sure.
Okay, so in order to do that
it's really all about here
and here.
Let's see, how do I want to reflect it?
I could use the scale function, right?
Like, push, let's just use push and pop just in case.
Pop, scale one negative one,
like would that reflect it around the,
whoops.
Oh, changes.
This used to work and now it doesn't.
By the way, it's push and pop in p5,
but in Processing it's pushMatrix and popMatrix.
Is this actually going to work?
Oh yeah, look at that.
It's reflected around the x-axis.
That's pretty cool, right?
So that worked.
Then what I want to do is, in addition to that,
I also want to do this six times.
So I'm going to say for int i equals zero,
i is less than pi divided by, oh two pi,
no, no, i is less than six.
Let's just use an integer, i plus plus.
Then I'm just going to say rotate
pi divided by six, right?
Oh that's wrong.
Rotate pi divided by three.
There we go.
Cool!
So now, we've got it kind of reflected
and kaleidoscoping.
Oh, this is fun.
Alright, so you can see how this is,
by the way, were kind of done.
(laughter)
It's just a matter of,
there's a few things I think
that are worth cleaning up here.
First of all, we're really going to have
to wait a really long time watching it,
although I really do like this kind of animation idea of,
like, watching it build up over time.
But there's also kind of an issue here,
like I really should constrain,
like I, this thing that's moving this way,
I think I want to constrain it within this slice.
Like I don't want to let it to go outside of the slice.
So in order to do that
while it's moving, updating,
I should, this is why it would've been good to use a vector.
Let's actually change this.
I'm going to say p-vector position,
and I'm just going to call it pos for position,
and then I can also make this x and y.
And I'm going to say pos equals a new p-vector x and y.
And then I'm going to say pos dot x, pos dot y,
and pos dot x, pos dot y.
And then s dot pos dot x.
Might be a more elegant way to do this.
Pos dot x, pos dot y, and pos dot x.
Okay, so this should be the same as what I had before,
but what I like about this is I can actually
get the angle now.
If I have it in a vector,
I can say the angle equals position dot heading.
And then what I could do is I could basically say
angle should be constrained
between zero and pi divided by six
'cause I kind of want a 30 degree angle there, I think.
Oh, and I want to constrain the angle,
and then I could just make a new vector.
So if I say the magnitude is the magnitude,
and then I can re..., there's probably a way
to like rotate the vector without making a new one,
but I can really just say now
pos dot x equals magnitude.
I mean I could make a new vector.
Pos equals p-vector dot from,
from angle angle.
And then pos dot set mag magnitude.
So this is not a very efficient way of doing this
because I'm making a new object,
but basically I'm just taking the existing vector,
whatever it is, like if this is it here
represented as this arrow,
I'm basically constraining the angle to here
and then making a new vector that looks like this,
so as it's wandering, it can't go past here
and it can't go past here.
Let's see if that works.
I mean, it's sort of hard to tell,
but it's going to, you know, is this really different?
I think we might see the difference
if I were to speed this up.
Oh, weird.
Oh I think I know what the issue is.
It's never going to go past zero, right.
I think it's never going to go past zero
because I'm constraining the angle
so even if it gets past zero, I put the angle back.
So look at this, it's never going to get past zero.
Eh, let's just make it less than one.
Let's make it never go less than,
where is that in update, in finished?
Yeah, let's just say less than one.
(chuckles)
Okay.
And ngramptz in the chat says
do you think randomizing the starting position?
Yeah, I definitely should randomize the starting position,
I think that'll be more interesting.
Okay, so this is working, working again.
Let's speed this up.
While current is not finished and it's not intersecting,
so I could like, I could basically
put a while loop here in draw that's basically saying,
like, keep updating.
Update, update, update until you're done.
Let's see.
Oh yeah, there we go.
Hey!
(rings bell)
Ta-da!
That's cool.
Wait, why is it...
I don't like, hold on.
I feel like it doesn't look very snowflakey.
We should rotate pi divided by three?
Yeah, no.
Pi divided by six?
There we go.
That's better.
It should be, that line should be vertical.
And you're right, it's not very,
it doesn't branch out so much.
Let's try some things.
One thing would be we could
kind of let it wander off further.
Yeah, that's kind of cool.
It's also the other thing that's happening here
is it's, just like, it's never ending.
It's never ending.
So what if we, okay.
So let's randomize the starting position.
So, again, if I were being sort of smart,
smart, probably the best way to do this,
I don't know what counts as best,
but it would probably make sense for me
to kind of randomize the starting position
along the path of this kind of circle
of radius width,
and then randomize a starting vector maybe
that points towards the center.
But I think I can get the same effect,
loosely the same effect by just,
kind of, randomizing the height.
So like what if I let it start between zero and 10 pixels.
Yeah, that's kind of nice.
I mean, this is very snowflakey.
(rings bell)
Okay, one more thing that I'm going to do,
let's just make this full screen.
Full screen.
Let's, oh, we should probably make
this height divided by two
because, oh that doesn't actually really matter,
width divided by two.
Let's try it.
Alright here we go, full screen.
Alright, here it is.
Here is your, whoa it's crazy
'cause it came out from so far.
Here is your snowflake generator.
(blows flute)
This is my in Processing Brownian Motion
Diffusion Limited Aggregation snowflake generator.
There is so much you could do now, right?
You could start to think about color.
You could start to think more about the sort of,
like, what if it were a vector
and you play with the velocity
or how you could constrain it,
how could you animate it in different ways.
But this is the basic idea.
Here we go, we now have a snowflake pattern
generated very fractal kaleidoscopey like thing
for the holidays.
Make your snowflakes.
Maybe you could even do something
where you make these much smaller
and save them as little PNGs
and then you have, you generate, like,
thousands of different snowflake patterns.
Alright, I'm sure you will come up
with some interesting improvements on this.
Please check the video's description
for a link at the coding-training.com
to where you can submit your own version of this,
and also there'll be a JavaScript implementation there,
and I encourage you if you enjoyed this video
to consider supporting the Processing Foundation.
Processingfoundation.org/support.
It could use your support.
Thank you very much and goodbye.
(rings bell)
(upbeat music)