[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]
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?