WEBVTT

00:01.080 --> 00:01.890
In this video,

00:01.890 --> 00:04.920
we are going to continue implementing Conway's Game of Life.

00:05.700 --> 00:07.710
We are going to look at the source code in this video.

00:08.130 --> 00:12.510
I thought it would only need one or two videos, but in fact, it has needed four.

00:12.570 --> 00:14.490
So, apologies for that.

00:16.590 --> 00:19.290
Let's start off by looking at live.h.

00:19.680 --> 00:22.470
This has all the parameters for the simulation.

00:23.370 --> 00:29.670
The characters for cell will be capital X, if the cell is alive, and a space if the cell is empty.

00:29.940 --> 00:31.080
Which seems appropriate.

00:32.430 --> 00:36.000
We are going to be displaying this on a standard ANSI compliant console.

00:36.630 --> 00:42.450
This has rows, which go from 1 to 24, and columns, which go from 1 to 80.

00:43.390 --> 00:45.970
We are also going to have a border of

00:47.080 --> 00:49.540
cells which are permanently unpopulated, around this.

00:49.600 --> 00:55.050
So that will correspond to row 0, column 0, row 24 and column 80.

00:55.510 --> 01:01.810
So the maximum possible row number for a cell that is going to be displayed will be 23, and the maximum

01:01.900 --> 01:03.970
possible column number will be 79.

01:05.080 --> 01:06.280
Then we have the parameters

01:06.280 --> 01:08.980
that Conway came up with. A live cell

01:08.980 --> 01:15.910
needs two or three neighbours to survive, and an empty cell needs exactly three live neighbours to become

01:15.910 --> 01:16.570
populated.

01:19.370 --> 01:20.720
In the main() function,

01:20.720 --> 01:24.200
we start off by telling the user what to expect, and what to do.

01:24.950 --> 01:27.020
Then we wait for them to press the return key.

01:27.740 --> 01:30.110
This is just the standard input.

01:30.560 --> 01:33.320
It will stop and wait until the user presses the return key.

01:33.650 --> 01:36.530
If they enter any other characters, then that will just be ignored.

01:37.560 --> 01:39.080
I will come back to this bit in a minute!

01:41.370 --> 01:46.830
Then we create a grid object, which will contain the first generation of cells.

01:47.790 --> 01:50.010
We populate these cells at random.

01:51.580 --> 01:53.860
And then we display this initial generation.

01:55.000 --> 01:59.440
Then we wait for the user to press the return key, when they are ready to go on to the next iteration.

02:00.850 --> 02:06.520
Then we create this object, which we use for calculating which cells will be populated in the next generation.

02:07.300 --> 02:12.070
And then we copy all the cells, from the next generation over our current generation.

02:12.610 --> 02:14.650
So we started off with the first generation.

02:15.040 --> 02:17.830
Then we calculated which cells are alive in the second generation.

02:18.430 --> 02:21.340
And then we copied all the cells over the current generation.

02:21.760 --> 02:25.450
So the current generation now has the second generation of cells.

02:26.110 --> 02:27.520
Then we go back to the start of the loop.

02:27.970 --> 02:28.720
We display it.

02:29.410 --> 02:30.100
Gets input.

02:30.520 --> 02:32.260
Calculate the third generation.

02:32.920 --> 02:33.590
Display that.

02:33.610 --> 02:34.940
And keep going on and on.

02:34.960 --> 02:35.500
And so on.

02:37.890 --> 02:41.550
The cell class is really just a wrapper around a Boolean.

02:42.300 --> 02:46.020
This will be true if the cell is alive, and false if it is empty.

02:46.920 --> 02:50.070
We have a constructor which sets the status to false.

02:50.430 --> 02:52.530
So by default, all the cells will be empty.

02:54.210 --> 03:00.480
We can draw a cell at a particular position on the grid. And then we have some getter and setter functions.

03:01.170 --> 03:04.500
So we can set the boolean to true, to make the cell alive.

03:05.160 --> 03:07.290
We can set it to false, to make it empty.

03:07.890 --> 03:10.530
And we can find out whether the cell is alive.

03:14.120 --> 03:20.120
To draw the cell, we use one of these ANSI escape commands, the one which will move the cursor

03:20.120 --> 03:21.050
to a given position.

03:21.890 --> 03:24.150
These commands were designed by engineers,

03:24.200 --> 03:25.250
so they start from one.

03:25.720 --> 03:29.300
Unlike computer scientists, which have our array starting from zero.

03:29.990 --> 03:34.370
So we need to add 1, to get the character displayed in the correct place.

03:35.690 --> 03:40.820
So we send this escape code to the screen, which will move the cursor to the correct position, and

03:40.820 --> 03:44.060
then we send the character that we want to display at that position.

03:47.270 --> 03:50.450
The grid has an array of these cells.

03:51.440 --> 03:55.760
We need to add 2 to the dimensions, to allow for the borders.

03:57.530 --> 04:00.620
We can create a cell at a given position.

04:00.630 --> 04:01.790
We can make it alive.

04:02.630 --> 04:04.010
We can draw all the cells.

04:04.820 --> 04:07.100
We can populate the cells at random.

04:08.360 --> 04:12.650
And we have some functions for calculating what happens in the next generation.

04:13.220 --> 04:15.460
This non-member function controls the process.

04:15.470 --> 04:17.870
It takes the old generation and the new generation.

04:18.620 --> 04:24.380
We have a member function which will determine whether a live cell will survive to the next generation,

04:24.890 --> 04:30.290
a member function which determines whether an empty cell will become populated, and then a member function

04:30.290 --> 04:35.300
which will update this grid object, with the data from the next generation.

04:39.660 --> 04:43.260
The create() function just calls the create() function for the cell

04:43.260 --> 04:44.190
in that position.

04:44.490 --> 04:46.580
So this will make that cell to come to live.

04:47.820 --> 04:50.760
If we are drawing all the cells, we need to clear the screen first.

04:50.940 --> 04:53.550
So we send the ANSI escape command for that.

04:54.540 --> 04:56.580
Then we iterate over all the grid's -

04:57.510 --> 05:00.420
then we iterate over all the cells, including the ones in the border.

05:00.840 --> 05:03.240
And then we draw each cell in the right place.

05:06.160 --> 05:08.140
For populating the cells at random,

05:08.440 --> 05:15.730
we iterate over all the cells in the visible grid, and then we do this calculation. And this will populate

05:16.000 --> 05:16.900
the cell.

05:17.710 --> 05:23.580
A factor of 5 means there is a one in 5 probability, so at 20% of the cells will be populated and

05:23.600 --> 05:24.910
80% will be empty.

05:25.810 --> 05:30.160
If we change this to 10, for example, then that will be a one in 10 probability.

05:30.400 --> 05:32.650
So the initial grid would be much emptier.

05:34.330 --> 05:39.580
I am not going to seed the random number generator here, because I want to get the same output every

05:39.580 --> 05:42.840
time. Because I want to test and demonstrate.

05:42.850 --> 05:44.620
And for that you need consistent output.

05:45.430 --> 05:50.470
Obviously, if you were doing this for real, you would uncomment this and seed the random number generator,

05:50.920 --> 05:52.990
so you would get different output every time you run it.

05:55.720 --> 06:01.240
Then we have this function for determining whether a live cell will survive to the next generation.

06:02.140 --> 06:04.240
First, we check that there is a live cell there.

06:04.510 --> 06:06.370
If the cell is empty, there is nothing to survive.

06:06.370 --> 06:07.540
So we return false.

06:09.380 --> 06:15.050
Then we go through the neighbours of this cell. We call the is_alive() member function and add up the

06:15.050 --> 06:15.550
results.

06:16.100 --> 06:19.260
And that will give us the number of live neighbours for that cell.

06:20.390 --> 06:24.440
If we have too many or too few, then the cell will not survive and we return false.

06:25.220 --> 06:30.320
And if we survive to the end of the function, then the cell will survive to the next generation.

06:32.950 --> 06:35.680
Then we have a very similar function for empty cells.

06:36.190 --> 06:38.410
If there is a live cell, we return false.

06:39.130 --> 06:41.230
We find the number of live neighbours.

06:41.920 --> 06:44.410
And if we have the right number, we return true.

06:44.410 --> 06:45.340
Otherwise false.

06:48.430 --> 06:49.540
The update() function

06:49.540 --> 06:55.330
just goes through all the visible cells in the grid, and it copies the value of the cell, from the

06:55.330 --> 06:57.910
new generation, into the current generation.

07:00.960 --> 07:04.380
And then we have this function, which oversees the calculation process.

07:04.560 --> 07:07.170
It takes the old generation and the new generation.

07:07.860 --> 07:14.250
It iterates over every cell in the grid, and then it determines whether the cell in the current grid

07:14.250 --> 07:14.940
will survive.

07:15.360 --> 07:17.370
And if so, it creates this in the new grid.

07:17.790 --> 07:19.860
And similarly for empty cells.

07:23.460 --> 07:27.840
Going back to the main function, there is some code which you need to uncomment, if you are using Visual

07:27.840 --> 07:31.680
Studio or anything else that runs in Windows Console.

07:32.580 --> 07:34.500
I will show you what happens first if you do not do that.

07:38.140 --> 07:38.710
So there we are.

07:38.890 --> 07:39.950
"Conway's Game of live."

07:39.970 --> 07:42.580
"Press the return key to display each generation".

07:43.870 --> 07:45.130
And then we get all this gibberish!

07:45.940 --> 07:49.450
So the Windows Console has received all these ANSI escape commands.

07:49.930 --> 07:53.290
But it does not know what to do with them, so it just displays them, without interpreting them.

07:57.010 --> 07:59.260
So I needs to include this ansi_escapes.h,

07:59.620 --> 08:01.750
which is this file.

08:02.200 --> 08:07.960
So this declares two functions, which will put the console into a state where it processes ANSI commands.

08:08.560 --> 08:11.320
And then, at the end, it will put it back to how it was initially.

08:12.280 --> 08:15.010
And I think I found this code on Microsoft's website.

08:15.250 --> 08:17.800
It is all low level Windows stuff.

08:18.610 --> 08:22.480
All the code for this simulation is available as a downloadable resource.

08:23.110 --> 08:27.370
So you can you compile yourself, look through it, and see for yourself how it works.

08:27.910 --> 08:30.280
I am not a Windows expert, so I am not going to go into this.

08:32.760 --> 08:34.740
So I need to include this file.

08:35.190 --> 08:38.970
I also need to set up the console, before we display any output.

08:40.720 --> 08:44.170
And then at the end, I need to put things back, how I found them.

08:45.820 --> 08:46.810
So let's try this again.

08:48.310 --> 08:49.120
Ah yes, that is much better.

08:49.930 --> 08:52.660
So if we look at this, we have the border around the cells.

08:52.660 --> 08:53.410
It is rather thin.

08:54.640 --> 08:58.150
Then we have a cell at row 1, column 1.

08:58.720 --> 09:00.760
This has just one live neighbour.

09:02.170 --> 09:04.570
This cell here has three live neighbours.

09:05.410 --> 09:07.030
This has one live neighbour.

09:08.080 --> 09:09.820
This has three live neighbours.

09:10.720 --> 09:14.140
And this has only two live neighbours. That one there is actually empty.

09:14.800 --> 09:18.580
So in the next generation, we expect these two will have disappeared.

09:18.610 --> 09:23.140
We have a cell there, and then two cells there. And nothing down here.

09:25.540 --> 09:26.110
And there we are.

09:27.070 --> 09:30.250
And then we keep on pressing return, to get through the generations.

09:35.230 --> 09:38.200
And you can see structures starting to appear like this one.

09:38.200 --> 09:39.790
So there are some stable structures.

09:40.300 --> 09:45.760
For example, if you have a ring, every cell in the ring has exactly two live neighbours.

09:46.150 --> 09:47.680
So these will keep each other alive.

09:48.130 --> 09:53.350
So a structure like this could survive for generations, unless some other structure comes along and

09:53.590 --> 09:54.310
disrupts it.

09:58.380 --> 09:59.730
So, like that.

09:59.730 --> 10:02.880
So you see, the ring has now been merged into a bigger structure.

10:06.000 --> 10:07.320
And then we have another one down here.

10:07.320 --> 10:09.090
This is another stable structure.

10:12.460 --> 10:14.290
So what can you do to improve this?

10:15.190 --> 10:19.330
Well, for example, you might want to leave this running for a long time to see what happens.

10:19.330 --> 10:24.880
And having to sit there and keep pressing the return key might get a bit tedious. So you could just run it

10:25.630 --> 10:28.300
in a flat-out loop, or you could put a sleep in, or a pause.

10:28.930 --> 10:33.430
And the way to do that will depend on your operating system, so you can look that up.

10:34.000 --> 10:38.920
Or alternatively, there is a way to do that in C++11, which I will cover later. So you can try that

10:38.920 --> 10:40.090
out for yourselves if you like.

10:41.110 --> 10:46.780
Another thing is, it is quite hard to keep track of which cells are appearing and disappearing between

10:46.780 --> 10:47.440
iterations.

10:48.280 --> 10:53.800
So you could have another grid, which you display in between the current generation and the next generation.

10:54.820 --> 11:00.940
And on this in-between grid, you have the cells which are dying in red, maybe. The cells which are

11:00.940 --> 11:04.360
being born in green, and the cells which survive in blue.

11:06.220 --> 11:11.260
I have chosen a solution which is easy to implement, but it is not very efficient or accurate.

11:11.800 --> 11:17.860
We have this border of empty cells around it, which stops cells wandering off the edge of the simulation.

11:17.860 --> 11:19.240
But that is not actually correct.

11:19.870 --> 11:25.450
If you look at the Wikipedia page for Conway's Game of Life, there are some ideas about how to make

11:25.450 --> 11:29.800
this more extensible, without using too much memory or CPU time.

11:30.520 --> 11:34.660
And there are also some variants on the Game of Life, variants on the Conway rules, and you could

11:34.660 --> 11:35.500
look at those as well.

11:36.730 --> 11:41.590
And of course, if you are into graphics or GUI programming, you can make this look a lot flashier.

11:42.610 --> 11:44.120
Okay, so that is it for now.

11:44.140 --> 11:45.700
I am doing control-C to escape!

11:46.300 --> 11:47.200
I will see you next time.

11:47.200 --> 11:49.320
But until then, keep coding!
