Skip to content

Commit

Permalink
Merge pull request #17 from alessandro-bugatti/life
Browse files Browse the repository at this point in the history
Life
  • Loading branch information
alessandro-bugatti authored Feb 1, 2019
2 parents 5e2100d + 37184e9 commit fb84b64
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 0 deletions.
102 changes: 102 additions & 0 deletions lessons/0040_game_of_life/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include <iostream>
#include <algorithm>
#include <ctime>
#include "../../vsgl2.h"

using namespace std;
using namespace vsgl2;
using namespace vsgl2::general;
using namespace vsgl2::video;
using namespace vsgl2::utils;

const int DIM = 64;
const int CELL_DIMENSION = 8;

int life[DIM][DIM];
int temp[DIM][DIM];


void start(int m[][DIM])
{
for (int i = 0; i < DIM; i++)
for (int j = 0; j < DIM; j++)
if (rand()%6 == 0)
m[i][j] = 1;
else
m[i][j] = 0;
//Put the border cells to zero
for (int i = 0; i < DIM; i++)
{
m[0][i] = 0;
m[i][0] = 0;
m[DIM - 1][i] = 0;
m[i][DIM - 1] = 0;
}
}

void draw(int m[][DIM])
{
for (int i = 0; i < DIM; i++)
for (int j = 0; j < DIM; j++)
if (m[i][j] == 1)
draw_filled_rect(i*CELL_DIMENSION, j*CELL_DIMENSION,
CELL_DIMENSION - 1, CELL_DIMENSION - 1,
Color(255,0,0,255));
}

int neighbours(int m[][DIM], int r, int c)
{
int counter = 0;
for (int i = r-1; i < r - 1 + 3; i++)
for (int j = c-1; j < c - 1 + 3; j++)
counter += m[i][j];
return counter - m[r][c];
}

void evolve(int m[][DIM])
{
for (int i = 1; i < DIM-1; i++)
for (int j = 1; j < DIM-1; j++)
{
int n = neighbours(m, i, j);
//Any live cell with fewer than two live neighbors dies,
//as if by underpopulation.
if (m[i][j] == 1 && n < 2)
temp[i][j] = 0;
//Any live cell with two or three live neighbors lives
//on to the next generation.
if (m[i][j] == 1 && (n == 2 || n == 3))
temp[i][j] = 1;
//Any live cell with more than three live neighbors dies,
//as if by overpopulation.
if (m[i][j] == 1 && n > 3)
temp[i][j] = 0;
//Any dead cell with exactly three live neighbors
//becomes a live cell, as if by reproduction.
if (m[i][j] == 0 && n == 3)
temp[i][j] = 1;
}
for (int i = 1; i < DIM-1; i++)
for (int j = 1; j < DIM-1; j++)
m[i][j] = temp[i][j];
}

int main(int argc, char* argv[])
{
//init the library
init();
//create the window and show it
set_window(DIM*CELL_DIMENSION, DIM*CELL_DIMENSION,"Vsgl2 Game of Life");
srand(time(NULL));
start(life);
while(!done())
{
draw(life);
update();
evolve(life);
delay(100);
}

close();
return 0;
}
41 changes: 41 additions & 0 deletions lessons/0040_game_of_life/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Game of Life
The classical [Game of Life](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) is a sort of mathematical "game" invented by John Conway in the seventies, that it will be used to show how to record information inside a matrix about the image to be displayed.

In a nutshell, there is a NxN matrix with 0 and 1s in each cell, where 0 mean *dead* and 1 mean *alive* (sometimes they are referred as *unpopulated* and *populated*). This matrix evolves with discrete steps, updating every cell at each step using these simple rules:
- Any live cell with fewer than two live neighbors dies, as if by underpopulation.
- Any live cell with two or three live neighbors lives on to the next generation.
- Any live cell with more than three live neighbors dies, as if by overpopulation.
- Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.

As a result, there is a feeling of moving things, because of the continuing change in cell values, as it can see in the below video

[![YouTube video on Game of Life](http://img.youtube.com/vi/OWfAzvJidVQ/0.jpg)](http://www.youtube.com/watch?v=OWfAzvJidVQ "YouTube video on Game of Life")

The code is quite simple, there are four functions that done all the job:

1. ```void start(int m[][DIM])```: populate all the matrix with 0 and 1s, using the the `rand()` function to choose between 0 and 1, with a ratio of 6 to 1, to avoid to overpopulate the matrix
2. ```void draw(int m[][DIM])```: put the entire matrix to the screen with the ```draw_filled_rect``` function. The coordinates of each cell depends on its *i, j* position, multiplicated for **CELL_DIMENSION**, in this case 8, to have cell that are clearly visible on the screen. Only cells with 1 inside are put on the screen, red coloured.
3. ```void evolve(int m[][DIM])```: this is the main function, which is in charge of evolving the matrix state using the rules explained above.
In particular there are four *if*, each one matching one rule
```c
int n = neighbours(m, i, j);
//Any live cell with fewer than two live neighbors dies,
//as if by underpopulation.
if (m[i][j] == 1 && n < 2)
temp[i][j] = 0;
//Any live cell with two or three live neighbors lives
//on to the next generation.
if (m[i][j] == 1 && (n == 2 || n == 3))
temp[i][j] = 1;
//Any live cell with more than three live neighbors dies,
//as if by overpopulation.
if (m[i][j] == 1 && n > 3)
temp[i][j] = 0;
//Any dead cell with exactly three live neighbors
//becomes a live cell, as if by reproduction.
if (m[i][j] == 0 && n == 3)
temp[i][j] = 1;
```
4. ```int neighbours(int m[][DIM], int r, int c)```: a little utility function to count how many neighbours cells are near to cell **m[r][c]**

Using all these functions is now easy to implement the main loop, drawing and evolving the state at each step.
74 changes: 74 additions & 0 deletions lessons/0040_game_of_life/vsgl2.cbp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="vsgl2_graphics_drawing" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Win32 Debug">
<Option output="win32/bin/Debug/provaSDL" prefix_auto="1" extension_auto="1" />
<Option object_output="win32/obj/Debug/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-g" />
</Compiler>
<Linker>
<Add option="-lmingw32 -lSDL2main -lSDL2 -lSDL2_net -lSDL2_image -lSDL2_mixer -lSDL2_ttf" />
</Linker>
</Target>
<Target title="Win32 Release">
<Option output="win32/bin/Release/provaSDL" prefix_auto="1" extension_auto="1" />
<Option object_output="win32/obj/Release/" />
<Option type="0" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-lmingw32 -lSDL2main -lSDL2 -lSDL2_net -lSDL2_image -lSDL2_mixer -lSDL2_ttf" />
</Linker>
</Target>
<Target title="Linux Debug">
<Option output="linux/bin/Debug/provaSDL" prefix_auto="1" extension_auto="1" />
<Option object_output="linux/obj/Debug/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-g" />
</Compiler>
<Linker>
<Add option="-lSDL2main -lSDL2 -lSDL2_net -lSDL2_image -lSDL2_mixer -lSDL2_ttf" />
</Linker>
</Target>
<Target title="Linux Release">
<Option output="linux/bin/Release/provaSDL" prefix_auto="1" extension_auto="1" />
<Option object_output="linux/obj/Release/" />
<Option type="0" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-lSDL2main -lSDL2 -lSDL2_net -lSDL2_image -lSDL2_mixer -lSDL2_ttf" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wall" />
<Add option="-std=c++11" />
</Compiler>
<Unit filename="../../vsgl2.cpp" />
<Unit filename="../../vsgl2.h" />
<Unit filename="main.cpp" />
<Extensions>
<code_completion />
<envvars />
<debugger />
<lib_finder disable_auto="1" />
</Extensions>
</Project>
</CodeBlocks_project_file>

0 comments on commit fb84b64

Please sign in to comment.