Up

A Simulation Program of The Game of Life

 

A sample program of The Game of Life was developed in Visual C++/CLR. The rules of the game (A. Bellos, 2015, Alex through the looking glass: How life reflects numbers, and numbers reflect life. Bloomsbury Publishing PLC, p. 262) are as follows.

Individuals are represented as small squares arranged in 2 dimensional array.

When an individual is dead, it will be live at the next time only if exactly three neighbors are live.

When an individual is live, it will be live at the next time if two or three neighbors are live, and will be dead otherwise.

 

Program files are compressed in GameOfLife.zip. The files in the .zip file can be extracted by clicking on the filename of the downloaded .zip file with the right button of a mouse (Figure 1).

From the menu items presented, choose gExtract Allch

Figure 1

 

When the project is opened by Visual Studio 2013, an error may be shown. But, this type of error can be neglected.

Detailed information about this is prepared at the website

http://mcn-www.jwu.ac.jp/~yokamoto/openwww/cpp/VCppGraphics/

 

When the program starts, a form shown in Figure 2 will appear.

Figure 2

 

Clicking or dragging on the pictureBox with the left button of the mouse makes the white square black. Black and White mean live and dead, respectively.

Clicking or dragging with the right button changes the black squares that are clicked or dragged to white ones.

After setting the pattern (Figure 3), click the Go button.

Figure 3

 

 

Simulation will start (Figure 4).

Figure 4

 

If you click the Stop button, simulation will stop. The form will be like Figures 2 or 3, i.e., the Stop button hides and the Go button appears. You can re-draw a pattern. After that, you can re-start the simulation by clicking the Go button.

 

Program files are as follows.

 MyForm.h 

#pragma once

 

#include "common.h";

 

namespace GameOfLife {

 

@@@E

@@@E

@@@E

 

#pragma endregion

        private: System::Void buttonClose_Click(System::Object^  sender, System::EventArgs^  e) {

                this->Close();

        }

 

                         int pw, ph;

                         Graphics ^ g;

                         Brush ^ bshWt;

                         Brush ^ bshBk;

 

                         int ms_st;

                         int cell_ck0, cell_ck1;

 

                         int cond_set;

 

 

        private: System::Void MyForm_Load(System::Object^  sender, System::EventArgs^  e) {

                pw = 500;

                ph = 500;

                pictureBox1->Width = pw;

                pictureBox1->Height = ph;

                pictureBox1->Image = gcnew Bitmap(pw, ph);

                g = Graphics::FromImage(pictureBox1->Image);

                bshWt = gcnew SolidBrush(Color::White);

                g->FillRectangle(bshWt, 0, 0, pw, ph);

                bshBk = gcnew SolidBrush(Color::Black);

                ms_st = 0;

                for (int st = 0; st < 2; st++)

                        for (int i = 0; i <= 101; i++)

                                for (int j = 0; j <= 101; j++)

                                        cell_state[st][i][j] = dead;

                cell_ck0 = 0;

                cell_ck1 = 1;

                cond_set = 0;

                buttonStop->Hide();

        }

private: System::Void pictureBox1_MouseDown(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) {

        int ix, iy;

        if (cond_set == 0){

                ix = (e->Location.X / 5);

                iy = (e->Location.Y / 5);

                if ((ix >= 0) && (ix < 100) && (iy >= 0) && (iy < 100)){

                        if (e->Button == System::Windows::Forms::MouseButtons::Left){

                                pictureBox1->Image = pictureBox1->Image;

                                g->FillRectangle(bshBk, ix * 5, iy * 5, 5, 5);

                                ms_st = 1;

                                cell_state[cell_ck0][ix + 1][iy + 1] = live;

                        }

                        else if (e->Button == System::Windows::Forms::MouseButtons::Right){

                                pictureBox1->Image = pictureBox1->Image;

                                g->FillRectangle(bshWt, ix * 5, iy * 5, 5, 5);

                                ms_st = -1;

                                cell_state[cell_ck0][ix + 1][iy + 1] = dead;

                        }

                }

        }

 

}

private: System::Void pictureBox1_MouseMove(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) {

        if (cond_set == 0){

                if (ms_st == 1){

                        int ix, iy;

                        ix = (e->Location.X / 5);

                        iy = (e->Location.Y / 5);

                        if ((ix >= 0) && (ix < 100) && (iy >= 0) && (iy < 100)){

                                pictureBox1->Image = pictureBox1->Image;

                                g->FillRectangle(bshBk, ix * 5, iy * 5, 5, 5);

                                cell_state[cell_ck0][ix + 1][iy + 1] = live;

                        }

                }

                else if (ms_st == -1){

                        int ix, iy;

                        ix = (e->Location.X / 5);

                        iy = (e->Location.Y / 5);

                        if ((ix >= 0) && (ix < 100) && (iy >= 0) && (iy < 100)){

                                pictureBox1->Image = pictureBox1->Image;

                                g->FillRectangle(bshWt, ix * 5, iy * 5, 5, 5);

                                cell_state[cell_ck0][ix + 1][iy + 1] = dead;

                        }

                }

        }

}

private: System::Void pictureBox1_MouseUp(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) {

        if (cond_set == 0){

                ms_st = 0;

        }

}

private: System::Void buttonGo_Click(System::Object^  sender, System::EventArgs^  e) {

        buttonStop->Show();

        cond_set = 1;

        timer1->Enabled = true;

        buttonGo->Hide();

}

private: System::Void buttonStop_Click(System::Object^  sender, System::EventArgs^  e) {

        buttonGo->Show();

        cond_set = 0;

        timer1->Enabled = false;

        buttonStop->Hide();

}

        private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {

                timer1->Enabled = false;

 

                for (int i = 1; i <= 100; i++)

                        for (int j = 1; j <= 100; j++){

                                int count = 0;

                                for (int i1 = -1; i1 <= 1; i1++)

                                        for (int j1 = -1; j1 <= 1; j1++){

                                                if ((i1 != 0) || (j1 != 0)){

                                                        if (cell_state[cell_ck0][i + i1][j + j1] == live)

                                                                count++;

                                                }

                                        }

                                switch (cell_state[cell_ck0][i][j]){

                                        case dead: if (count == 3){

                                                                        cell_state[cell_ck1][i][j] = live;

                                                                }

                                                           else{

                                                                   cell_state[cell_ck1][i][j] = dead;

                                                           }

                                                           break;

                                        case live: if ((2 <= count) && (count <= 3)){

                                                                        cell_state[cell_ck1][i][j] = live;

                                                                }

                                                           else{

                                                                   cell_state[cell_ck1][i][j] = dead;

                                                           }

                                                           break;

                                        default:   break;

                                }

                        }

                pictureBox1->Image = pictureBox1->Image;

                for (int i = 0; i < 100; i++)

                        for (int j = 0; j < 100; j++)

                                if (cell_state[cell_ck1][i + 1][j + 1] == live){

                                        g->FillRectangle(bshBk, i * 5, j * 5, 5, 5);

                                }

                                else{

                                        g->FillRectangle(bshWt, i * 5, j * 5, 5, 5);

                                }

 

                if (cell_ck1 == 0){

                        cell_ck1 = 1;

                        cell_ck0 = 0;

                }

                else{

                        cell_ck1 = 0;

                        cell_ck0 = 1;

                }

 

        timer1->Enabled = true;

}

};

}



 

The three dimensional array cell_state, which stores patterns of states of individuals, is declared and defined in the separate files common.h and common.cpp from the header file MyForm.h to avoid errors.

If the array were declared as a member of the ref class form or out of the declaration of the ref class form, the compiler would produce an error message.

 

 common.h 

#ifndef COMMON_CK

#define COMMON_CK

 

enum Cell_st {live, dead, other};

 

extern Cell_st cell_state[2][102][102];

 

#endif



 

 common.cpp 

#include "common.h"

 

Cell_st cell_state[2][102][102];

 



 

Effects of drawing with Graphics handle g may fail to be reflected on the display, when drawing is done after some interval of the previous setting of the Image property.

To avoid this unsuccessful drawing after some interval of the previous setting of the Image property, set the Image property of the pictureBox again before drawing.

Before drawing, setting the Image property like this

pictureBox1->Image = pictureBox1->Image;

will make effects of drawing to be reflected on the display.

 

Speed of the simulation is controlled by a timer component.

 

Up