Coding Challenge #127: Brownian Tree Snowflake

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
(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 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. Go particle, go, stop. Go particle, go. Go particle, go. 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)
Info
Channel: The Coding Train
Views: 76,444
Rating: undefined out of 5
Keywords: programming, daniel shiffman, tutorial, coding, the coding train, coding challenge, coding train, creative coding, code challenge, creative coding tutorials, programming challenge, brownian tree, brownian tree snowflake, brownian snowflake, snowflake generator, computational snowflake, snowflake drawing, snowflake coding challenge, code golf snowflake, snowflake processing, processing challenge, processing coding challenge, diffusion limited aggregation, computer science
Id: XUA8UREROYE
Channel Id: undefined
Length: 19min 25sec (1165 seconds)
Published: Mon Dec 24 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.