Coding Challenge #85: The Game of Life

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

I've found an issue with this in that it doesn't take very long from the program to get "stuck" in that there are a few that are in a permanent state of being alive and all the rest are dead. I think this can be resolved by checking how many cells are alive and if the number doesn't change for a certain number of frames then randomly adding new cells. Does that seem right to anyone else?

👍︎︎ 1 👤︎︎ u/tehnod 📅︎︎ Dec 11 2017 🗫︎ replies
Captions
[TRAIN WHISTLE] Hello, welcome to today's coding challenge. In today's coding challenge, I'm going to attempt to program this, the game of life cellular automaton in JavaScript. Going to use the P5.js framework. What's running right here right now is a processing example using the Java programming language that I made several years ago as part of The Nature of Code book. Now, if you're interested in that, you can also look at my whole playlist about this thing that I can't pronounce called cellular automata, the plural of automaton. And I do have some videos that give you some historical background, and looking at different Wolfram's elementary CA, and some exercises and things. But I'm really just showing examples and talking about the systems in those videos. In this video, I'm going to try to start from no code and finish with the simulation. Hopefully it's going to work. It generally doesn't. So don't get your hopes up. But I do want to say that I would encourage you to do some background reading. This is the first public appearance of the game of life as created by John Conway, a mathematician, from an article in Scientific American in 1970 by Martin Gardner. Of course, you can always refer to the Wikipedia page. I'm going to need this, which is going to-- which outlines the rules for how the system behaves. And you can also see that there's a lot of possible stuff. There's all these kinds of interesting repeating patterns and different types of things that you could create and do with the Game of Life simulation. But I'm going to program a simple version of it. Hopefully that will happen. Then at the end, we'll talk about some variations that you might think about. And maybe someday I'll try to make one in 3D or something like that OK, so let's get started. Here's what we need. A cellular automaton is a system of cells that exist in a grid. It could be in one dimension, two dimensions, three dimensions. The Game of Life system is one that exists in two dimensions. And the idea is that you have generations. So if this is generation 0, I'm going to run some computation on this system of cells on a grid. And then I'm going to have a new set of cells on that grid. And that's going to be generation 1. So the cells that exist on that grid all have a state. That's part of a CA system. So that state could be a floating point number. It could be a kind of animal. You could really imagine a lot of different ways. I'm going to do something very simple with the game, of The Game of Life is a simple system of discrete states, two states, 0 or 1, on or off, alive or dead. So you can imagine a configuration of this being something like this. And for each time, each tick, each generation, each frame of animation, I evaluate each cell one by one and get a new state based on the previous state. So once I'm trying to do this cell, I need this cell's new state, I'm going to get a new state based on this state and its neighbors. So what are its neighbors? That's up to us to define. It could be its left neighbor, its right neighbor, only its neighbors to its left. But in The Game of Life system, its neighborhood area are the eight cells surrounding it. So it's this 3 by 3 area, 1, 2, 3, 4, 5, 6, 7, 8. So I need to evaluate all of those cells and decide whether it should stay as the 0 or turn into a 1. And the reason why it's called The Game of Life is the rules. The rules for how we move from one generation to another resembles some type of biological process that you might think about, population or bacterial growth. And the idea is that a cell that is surrounded by neighbors that aren't alive cannot stay alive. A cell surrounded by neighbors that are alive can come to life or stay alive. And a cell that's surrounded by too many neighbors cannot stay alive due to overpopulation. And we can go back to the Wikipedia page and read those rules precisely right here. So any live cell with fewer than two neighbors dies, as if caused by underpopulation. Any live cell with two or three neighbors lives onto the next generation. Any cell with more than three neighbors dies by overpopulation. And any dead cell with exactly three live neighbors becomes a live cell. So this is written as if by reproduction. So this is written in somewhat of a confusing way. I think I could simplify this, I think. We could say let's say the cell is dead. It's a 0. It's only going to change to a 1 if it has three live neighbors. Then it changes to a 1. Otherwise, it stays a 0. A 1 is going to stay a 1 unless it has less than two, less than two live and greater than three live. Then it dies. So birth, reproduction, happens with exactly three neighbors. Death happens with fewer than 2 or greater than 3. Now, I don't know if I got those numbers right. Let's go check the Wikipedia page again. [FANFARE] Thank you, thank you, I hit the sound effect by accident. Live cell with fewer than two live neighbors dies. Yes, less than two dies. Live cell with two or three neighbors lives. I don't care about that. I'm not going to kind of not care about change-- that it stays the same. I can kind of ignore that. Live cell with more than three neighbors dies. Yep, that's what I've got over there. And then, any dead cell with exactly three live neighbors becomes alive. OK, so I've got those rules correct. So now, what do I need? You're over there. I'm going to go back over here. I need something. I need a-- all I need to make this program work is a data structure to store this grid. And this is where I'm having a bit of a headache. I'm really not sure what to do. The way that I've always done this in previous examples is by using something called a two dimensional array. I think I have a video tutorial about that somewhere, which I will link to in this video's description. But two dimensional arrays are kind of not so much fun in JavaScript. They can become a little bit weird. And there really is no such thing as a two-dimensional array. A two-dimensional array is a construct of our own human mind, saying it's really just an array of arrays, which makes sense. This is an array. Each row is an array. And then the grid is an array of rows. Or each column is an array. And the grid is an array of columns. So I think I'm going to do it that way with the two-dimensional array. I just should say that it's a little bit awkward, two-dimensional arrays in JavaScript. But I'm going to go ahead anyway. So the first thing that I want to do in this program is just make a two-dimensional array that stores a random collection of 0s and 1s. So let's go to that. I'm going to go to the code. And you know what I'm going to do? I'm going to actually just write a function. I'm having weird deja vu. I probably did this in another video somewhere. I'm going to just write a function called make2Darray. And I want a certain number of columns and rows. Because that way, I can just say, I can have a global variable called the grid. I'll call it grid. And I could just say grid equals make2Darray. And I could say, I want a 10 by 10 grid. So this is kind of what I want to do. I'm going to just farm out the making of the array to another function. And now I do remember doing this. Because I'm going to write this in a kind of-- oh, there's a whole coding challenge or video. I'm going to do this in kind of horrific way and then everyone's going to give me all these like amazing ES6 JavaScript fancy ways of doing this whole function in one line of code. Someday, I'll come back and do that. OK, so now, let me see here. So what I need to do first is I need to have some sort of array. And it's going to be-- this is always where I get confused, too. Do I want the columns-- the point of using a 2D array is that eventually at some point I would be able to say something like, grid know index 2, index 3. And I guess I usually think of this as x and y and x being the columns. So I want this, the outer array, if I think about arrays of arrays, to be every single column, every single-- no, no, that's-- x is column. And then the y is every single row. So I'm going to do that. So I'm going to make a new array of columns. And then, I am going to say for let i equal 0, i is less than that arr.length, i plus plus. Make array index i is a new array of rows. Again, I know there are all sorts of shorter and fancier automatic functions for generating and configuring arrays, like fill, and map, and reduce, and all that kind of stuff, even more. So I'm going to do this. And then I am going to-- what I want to do here now is also want to fill them with-- I guess I could fill with values down here. So maybe I won't. Maybe I'll actually just do that. So this is going to make me an empty 2D array with nothing in it. And then I think what I want is I probably want to have these global variables. I know this is a little bit goofy that I'm doing this. And then what I'm going to do, I could make an-- and I'm going to say let i equal 0. i is less than columns, i plus plus. And then I'm going to do j is less than 0. j is less than rows. I'm going to do a nested loop. So that I can say grid i j equals floor random 2. This is going to give me a nested loop. This is a nested loop. So I make this sort of 2D array structure that's empty. And then I integrate over every single column in every single row. And I fill each one with a random number, 0 or 1. And I'm just-- now I'm going to run this. And I'm going to go back to-- I'm going to go to my code. OK, cannot read property 0 of undefined. Well, you know it would be nice? If I actually returned that array. So the make 2D function array, it's making this array. It's also got to return it. So that I can get it back here. And then now, if I look at grid, I'm going to see, it's an array of arrays. And I forgot, there's this wonderful thing you can do, console.table grid, which shows me. Now I can see it here. So we can see this is that two-dimensional array. That's what it looks like. It's a two-dimensional array with rows and columns, filled with 0s and 1s. So Step one is finished. Now, what I need to do is I need some mechanism to, every frame of animation, iterate over every single spot and set a new spot. Actually, you know what I need to do first? I need to render this thing. I want to be able to see it as a grid of red and blue squares, or black and white squares, or 0s and 1s on the screen. There's any number of ways you could render this. I'm going to do it in the traditional way of a grid, the square, the cell of the grid is black. If the value of 0, is white with a value of 1, or vice versa. OK, what I want to do now is I'm going to add a draw function. And I'm going to be using this loop over and over again. I'm going to add this loop. Because I'm always going to-- any time I want to look at everything, I'm going to go through all the columns and all the rows. It's been pointed out in the chat that there are some JavaScript libraries and packages that manage grid systems and neighbors for you. Would be great to use those. I'm going to just do it all without that right now, just to kind of figure it out. I'm going to say background 0. And I'm going to create a canvas. I think, to make my life easier for the moment, I'm going to make the canvas also a square. And then what I need to do is I need to draw-- I want to draw a rectangle at an x and y with some width and height. And it's going to-- they're going to be squares, so some width and width. And that value is going to be the width of the-- I should probably calculate the number of columns and rows. Here's the thing. I'm going to redo the way that I'm doing this. So I'm not going to actually have a fixed number of columns and rows. I'm actually going to do like a scale. I'm going to just have a variable called resolution. And say that's 10, or 40. I'm going to say that's 40. So that'll be 10 by 10. And what I'm going to do is I'm going to say columns equals the width of the canvas divided by resolution. Rows equals the height of the canvas divided by resolution. This way, I can kind of dynamically-- you'll see what-- I can dynamically make a 2D array based on how big I want the squares to be. So the columns and rows are being calculated based on how big I want the squares to be and the canvas size. And then I have that global variable resolution, which is probably too long of a name, which I can just use down here. And now, x equals i times resolution and y equals j times resolution. And I'm going to now say if grid i j equals 1, fill 255. And you know what, since I made the background 0, I can actually, in this case, I can just draw white rectangles only for the values of 1. So let's see, I probably got something wrong here. But let's try to run this. No, I didn't. So we can see there we go. There's some goofiness, oh, it's sort of like my math is a little off. And what's this weird nonsense over here, flickering? I kind of feel the need to fix that. And the other thing that I can do that this is going to help is if I make this 600 by 400, and I make this 20, it still works. Now, this is driving me crazy. I think what I want to do is there's an issue with the stroke. So I could say, I could also say stroke 255. And then I'm getting something like this. But I don't know, design wise, I'm not going to worry about that too much. Actually, I kind of like being able to see the grid. So let me actually put in stroke 0. And then I'm going to do something kind of goofy, which is, I think if I say just draw all the rectangles one pixel less, I think I'm going to get the look that I want. Yeah, so whatever, there's countless ways I could deal with this. But now I have the grid. I have all the cells. So now it's up to me to simply implement these rules. I need to, for every single cell, count the number of live neighbors, look at its own state, and have these rules play out. Here's the thing, this is really important. While I'm checking each cell, I check this cell first, let's say, I cannot change its value and then go on and check the next cell. Because the next cell's new state should not be dependent on this cell's new state, but its previous state. And if I change the state, I have lost its old state. So this is where what I actually need is I need two two-dimensional arrays. One is the sort of old one. And one is the new one. Now, probably the simplest thing for me to do is just make a new one every frame. That's sort of like, in some ways, a bad idea in terms of memory management. And if you look at my processing example that I referenced at the beginning of this video, what I actually do in that example is I just have two different arrays. I have an old one and then I have a new one. Then the new one is then the old one. And I write the new one over here. I just keep swapping them. So I could maybe add that in at some point during this video. But for right now, at the beginning of draw, I'm just always going to make a new generation. At the beginning, what I can do here-- [FANFARE] Why's that keep happening when I press the button to change the camera? At the beginning of draw, I can say let next, for next generation, equal make2Darray columns and rows. Now, I'm going to leave this here for the rendering. And what I'm actually going to do is at the end, what I'm going to do is I'm going to say-- I guess it doesn't really matter. Do I want to render first? This is like a deep philosophical question. Do I want to compute and then render or render then compute? Kind of could matter in some situations. In this situation doesn't really matter. But the reason why is I'm never going to see the first generation. Because what I want to do is say grid equals next. So basically, the algorithm here is compute next based on grid. Because draw is looping. So I want to compute the next generation based on the grid, make grid that, render. And then compute the next generation based on grid, make grid, render. So I don't know, that's bothering me. I'm going to do this-- I'm going to do this after. So at least I draw the first one. And I'm going to do some computation for the next frame. OK, so now, what do I need to do once again? Loop through all of these, loop through all of these. Now, what I need to do is count live neighbors. I need to count the number of live neighbors, the neighbors that have 1. So I could do a kind of internal loop here. And that would probably be a smart thing to do. Maybe I will do that. Where basically what I do is I say I have a certain-- I'm at a certain cell, let me look at the cells between negative 1 and 1, negative 1 and 1, offset from where I am. I could also just do something really silly. Let me do the really silly thing first. I could say let sum equal 0. Then I could say sum plus equal grid i minus 1 j. That would be the neighbor to the-- so right, if this is i, j, i minus 1, j is there. i minus 1, j minus 1, i, j minus 1, that sort of thing. So if I'm thinking about this, I might add-- I could manually put in all the neighbors, just add them all up. This is like going around the horn here. Plus i plus 1, j plus 1, i-- sometimes I like doing ridiculous things like this just to figure this stuff out. Now, I got to go i minus 1, j plus 1. And then what's the last one? i minus 1, j. This should be eight neighbors. This is eight neighbors, 1, 2, 3, 4, oh, wait, 1, 2, 3, 4, 5, 6, 7. What did I forget? i minus 1, j minus 1, i, j minus 1, i plus 1, j minus 1. I forgot to do that whole top row. And then i plus 1, j, i plus 1, j plus 1, i. Yeah, so this should now be eight. 1, 2, 3, 4, 1, 2, 3, 4. I kind of hate that I did this. You're all throwing your tomatoes at your television screen, because of course, you're all watching this on the television screen. So this is the idea. I need to add up all those neighbors. Let's do this in a loop. So another way I could do it is I could say. I have a better idea. Neighbors, I have a better idea, let's write a function to do this, neighbors equals count. I'm going to give it the grid. And I'm going to give it the i and the j. So I'm going to write a function, I'll put it all at the bottom of my code, that receives I'm going to call it count, countNeighbors, let's call it. And it's going to receive some 2D array. And it's going to receive an x and y location. And then what I'm going to do is I'm going to say i equals negative 1, i is less than 2 i plus plus. Then so I'm going to do a little nested loop using i and j around that spot. And I'm going to say let sum equals 0. And then I'm going to say sum plus equals grid i, j. However, here's a problem. I don't want to count myself as a neighbor. So there's a few different ways I could do this. But it's a little bit silly. I'm just going to subtract it at the end. I'll just subtract it out. I could have put an if statement here, ignore it if i equals x and j equals x, but I'm just going to subtract it out at the end. And then I'm going to return that sum. So this is-- you could see a couple different ways of doing this right now. This is one way to kind of do this. What this is doing is it's saying let me do a little loop around here, negative 1, 0, positive 1, negative 1, 0, positive 1. So let me check this, this, this, and then subtract this out, because I don't really want to count that one. So now, I should be able to-- I'm going to just delete this. I've now counted all of the neighbors. I've got a big problem. What do I do with the fact that if I'm on the edge, there's no neighbor to the left? If I'm on the bottom, there's no neighbor below. From the top, there's no neighbor to the above. On the right there's no-- if I'm on the edge, there's no neighbor to the right. So what I could do, there's a bunch of things I could do. I could consider this like an infinite wraparound world, where this neighbor to the right is this. This neighbor to the left is this. I could-- there's other ways that I could approach it. What I'm going to do is I'm going to leave the edges as fixed values and just not bother to check them. So what I'm going to do here is I am going to-- I wanted to do, I was going to do this loop like this. You know what? Let's do the wraparound. Do I-- no, no, no let's do it the simple way first. I was like, oh, I'm just going to add the wraparound code. Because I could add the wraparound code here. But let me-- maybe I'll leave that as an exercise or do that later. The issue is you know what I really want? I think then-- the problem is if I change this loop. So I have to-- I have to treat the edges differently. Oh, so much heartache here. But I can say, what I'm going to do here is I'm going to say, oh this is the drawing. Oh, right, this is the computation. So I'm going to say if i equals 0 or i equals columns minus 1, minus 1, or j equals 0 or j equals rows minus 1, this is all of the edges. Just going to treat them differently. I'm going to say next i j equals grid i j. So I'm just going to keep the same values from before. This is not a great solution. But it's a quick one that I can do right now. So if I'm on an edge, I'm just going to use the same value. Because now, what I can do is say, look at this, my state is grid i j. Now it's time for me to implement those rules. OK if my state is 0, and 3 neighbors are alive, change my state to 1. If state equals 0 and neighbors equals 0, then next i j equals 1. That's rule number one. Not 0, equals 3. Now, what else? If I'm alive and less than 2 or greater than 3, are alive, then change my state to 0. Else if my state is 1 and neighbors is less than 2 or neighbors is greater than 3, and I probably should put a little parentheses around that one, and again, I'm sure there are some nicer ways I could write this in a more concise way. But you can see, this is the rule. If I'm alive, and I have less than 2 or greater than 3 neighbors, then the new state is 0. In all other cases, the next state is just the current-- is just the current state. So this makes me want to put this up here at the top. So that I can also just use this here. So that's the state. The state, this is the current state. If I'm an edge, just ignore me. I'm the same state. If I'm not an edge, count all the neighbors. Check if I should change my state or say the same. I'm seeing in the chat there's a typo at neighbors in the first if. Thank you, neighbors. What's the chance I've actually finished this? So there we go. I think I have mostly all the code for it. OK, count is not defined. sketch.js, line 55, oh right, because I called it countNeighbors, which is a better name for the function than count. Try that. Cannot read property negative 1 of undefined at countNeighbors. So what is undefined? Oh, no, no, no, no, look at this, this is a big mistake? What was I doing here? This loop-- negative, this loop, which goes, which is basically a loop for a little subsection, if this is x and y, i is an offset negative 1 to positive 1. j is an offset negative 1 to positive 1. The cells I'm looking at are not i j, but x plus i and y plus j, because I'm just looking relative to where that x, y point is. So that was a big mistake here. This should be x plus i, y plus j. Oh, so close. countNeighbors at draw sketch line 55. Line 55, countNeighbors, wait, whoa, cannot read property negative 1 of undefined. What's undefined? Grid? Neighbors? OK, hold on. Let's look at some stuff here. Or if j 0. Oh, look at this. I just keep going anyway, so this, I really, I need to break out of the loop. So this is really like I'm done. Leave the loop, or continue, or something. I don't know. I'm going to-- I'm just going to put an elf in here, as much as I hate that. Because I shouldn't be-- I'm basically doing the edges or the neighbors. Boy this would be much nicer if I just, in this function, add some code to deal with wraparound, which is not going to be that hard to do. So now, it should be good. There we go, the game of life. Now, it looks weird. Because the edges aren't ever changing. But this is actually now the game of life working. I really got to implement this wraparound thing. So let's do that now. Let's fix it so that the edges consider the other sides as neighbors. So how do I do that? Well, one way to do that is with something called modulus. This is really, this is great. And I can refer you to Golan Levin's guest tutorial video on modulus, which was made as part of this channel. So I will link to that. But basically what I'm saying here is if I have 10 columns, 0 through 9, what could-- and I'm always looking for the neighbor plus 1. So 0 plus 1 is 1, 1 plus 1 is 2, et cetera, et cetera, et cetera. 9 plus 1 is 10. But I want the neighbor to be 0. Well, guess what? 9 plus 1 modulus 10 equals 0, because modulus is the operator gives you the remainder of division. 10 divided by 10 is one remainder 0. So I encourage you to watch that modulus video, if you're not familiar with modulus. So this will actually work, almost, getting closer, if I say, I'm going to just say, I'm going to have a new-- I need a new variable name for x plus i-- I guess I could say column. I don't-- column. And I'm going to say x plus i modulus columns. And row equals y plus j modulus rows. So this gets me close. It doesn't get me all the way there. But it gets me close. So now I'm adding it up like this. And I'm going to get rid of this whole edges thing, because no longer. So I've got to get this-- Now, I'm going to have an error here. Right, I'm still getting an out of bounds area, because I'm going to negative 1. Why? Because what if in the case of i equal negative 1? So what if-- if i is 0, so let me come to the console here. 10 modulus 10 is 0. But let's say I'm looking for the left neighbors. So I'm going through negative 1, negative 1 modulus 10 is negative 1. But I need that to be 9. I need negative 1 to the 9. Well guess what? If I actually just add the number of columns to everything, if I'm actually working with the numbers, instead of the number 0 through 9, the numbers 10 through 19, 10 minus 1 is 9, modulus 10 is 9. So the formula is negative 1-- is negative 1 plus the number of columns modulus the number of columns. Oh but there's not 10. There's different numbers in my system. So let's try to confirm this again. The idea is that I have an x and a y point. So that point might be, let's say if it's on an edge, for example, might be like 0, it's on the left edge, might be something like 0, whatever the y is, 5. So this is the x value. And I want to take x plus i plus the number of columns modulus the number of columns. I said it was going to be simple. But it's kind of. It's really kind of a crazy thing to do. But you might write this out, practice it a bit on your own. It will make sense to you eventually. So when this is going to work, basically, let's say, i is going to be the values negative 1, 0, and 1. x is going to be the values 0 through 9 if I'm thinking about all the possible, all the possible columns. So let's just take 0 and negative 1, for example. 0 minus 1 plus, and in this case, I have 10 columns, plus 10 modulus 10 is actually 9 modulus 10, which equals 9. So 0 negative 1, to the left of it, that wraps it around to get the neighbor on the right. Doesn't work for just any arbitrary thing in the middle. If I take i to be 3-- sorry, if I take, sorry, x to be 3, 3 minus 1 plus 10 modulus 10. well see how this 10 and 10 kind of cancels itself out? Can you see that? Am I off the whiteboard? I'm close to being off the whiteboard. That equals 2. Because this is 12 modulus 10 is 2. So this actually works. And then what if I'm on the edge? If I'm at 9, right, if x is 9, 9 plus 1 is 10, plus the number of columns is 10, is 20, modulus columns, 20 divided by 10 is 2 remainder 0, so 9 to the right gets neighbors 0. So this is kind of goofy. It shifts everything over, so it can kind of look across the edge. So this is going to work. You can believe me or not believe me. But it's going to work. And I'm going to put this in. So now what I want is x plus i plus columns, modulus columns, y plus j plus rows modulus rows, add those all up. And the game of life. [FANFARE] Thank you, thank you for watching this coding challenge. Thank you, thank you. So let's try and make-- let's try doing a couple of things, just to get a little further here. I don't know, no, I'm not going to-- you do all the next stuff. I'm just curious let me make the resolution 10, so we can see that's with a 10. So we can see it's running pretty fast in the browser. I have a pretty low resolution. So here's what you should do now. I'm going to stop. This is a perfect opportunity for people watching this video to make some variations. Some things you can think about. Well, one thing is what if you make each one of these cells an object? So its state might not actually just be-- it can keep track of more than just its state 0 or 1. It could keep track of whether it's changed state, or stayed the same, or how long it stayed the same. What if you visualize those? What if you visualize with different colors based on the history of the system? What if you allow a user to draw with the mouse, set cells on? What if you look up some of these repeating, special repeating patterns that you can create certain kinds of patterns? What if you-- you're going to think of more. And what if you did the edges in a different way? What if you used a floating point numbers instead of 0s and 1s and did an average or something? There are so many ways you can create a system, lowering the resolution. What if you drew-- didn't draw squares, but circles, used images. How can you visualize this system? How can you change the rules or how can you visualize the system in a different way to create a piece of art or for some other purpose? I look forward to-- share what you make in the comments. There will be the code link from here and a Read Me where you can submit your versions. And I'll come back in a future livestream. I'll share some of the community made versions. Run this again. There's one other thing. But I do think that making cell objects is a path. Right now, I just have-- oh, and you should probably do the swapping thing. Maybe that's one other thing you could do is maybe don't make a new 2D array every time. But what I'm thinking about here is what if instead of each one of these being a random value, you said something like new cell, i, j. And this cell object can animate. It can move around. The cells could move, they could grow, they could shrink. They could keep track of their history. There's so many possibilities there if you make an object for the cell. OK, Thanks for watching. I hope you enjoyed this coding challenge and you share with me what you make. Goodbye. [MUSIC PLAYING]
Info
Channel: The Coding Train
Views: 459,399
Rating: 4.9403496 out of 5
Keywords: JavaScript (Programming Language), live, programming, daniel shiffman, creative coding, coding challenge, tutorial, coding, challenges, coding train, the coding train, live stream, itp nyu, this.dot, game of life, conway game of life, game of life js, game of life javascript, object oriented programming, the game of life, cellular automata, cellular automaton, john conway, simulation, 2d array, modulo, modulus
Id: FWSR_7kZuYg
Channel Id: undefined
Length: 38min 19sec (2299 seconds)
Published: Mon Dec 11 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.