"A Game of Life" to be used in the real life.
Tags: life, go, programming
Published: 2022-02-08 15:30:57

##Introduction

Famous "Game of Life" been an inspiration for a generations of mathematicians, computer programming geeks, scientists and people alike. But what about put this algorithm to a practical use ? By someone who do not holding a postdoctoral in mathematics... I already [proposed](https://www.therelicans.com/vulogov/a-life-with-a-twist-mc4) a slightly modified rules, to help to make this algorithm to become a practical instrument, and now, I am proposing an implementation in Golang, which will make that you will be able to use that algorithm in your practical applications, written in Go.

##Architecture

All elements of the Go module [github.com/vulogov/GoLife](https://github.com/vulogov/GoLife) implemented as a structures with interface functions to those structures.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3ger7gsanbv3v22ypzot.png)

###Implementation of the Cell
Each Cell is placed in the world and do have an X and Y coordinates in this world. Those coordinates could be obtained with interface functions *X():int* and *Y():int*. World do have a limited size and  is convoluted. More about World later. In addition to the coordinates, each Cell have a name. Name is set with interface function *SetName(string):* and could be obtained with interface function *Name():string*. Name do not play any particular role in the game logic. You can set any name as string to a Cell. When world is created, all Cells in the World do have coordinates, but not a name. So, the name is an abstract, that is relevantly used outside of GoLife module.

Next and very important attribute is a *status*. This attribute holds value *false* if Cell is dead, or *true* if Cell is Live. The value of the *status* attribute could be obtained with an interface function *Alive():bool*. Attribute *age* and related function *Age():int* will give you access to the Age of the Cell. When Cell changes the status, Cell Age is reset to 0. Each step in the "Game of Life" increase Cell Age to 1.

Next group of attributes dedicated to the Cell immunity to an unfavorable condition. Attributes *upImmunity:int* and *opImmunity:int* are holding the current "under-population" and "over-population" immunities thresholds. If Cell is detected to be a subject to a under-population or over-population, it will not die immediately. Instead of that, with each step of the Game, value of ether opImmunity or upImmunity will be decreased to 1. If Cell is Live and one of those counters goes 0, Cell changes status to the Dead. Immunity assigned to the Cell during the process of bringing Cell to Life. Two random numbers are generated and there values are from 0 to maximum Immunity threshold, defined for the World.  *upImmGiven:int* and *opImmGiven:int* are holding initial immunity given to the Cell when the Cell comes to Life. The purposes of those attributes are, if in the World we enable Cell recovery, then if Cell "health" been compromised by unfavorable condition, but did not become 0, which is threshold for Death, when Cell go back into a favorable condition, *upImmunity:int* and *opImmunity:int* will be increased to 1 with every step while Cell is in healthy condition, until those values will reached initial values defined in *upImmGiven:int* and *opImmGiven:int*.

The last pair of useful attribute/function is a *degrading:bool* and Degrading():bool*. If Cell is Live and in unfavorable condition, but immunity is not yet compromised, this function returns *true*, otherwise if Cell is Live and is in favorable condition, it returns *false*

Interface function *Step():bool* brings Cell to the next Step. 

If Cell is Live and it's age reaches limit, which is set to the World, Cell will "die of old age" and become Dead.

Interface function *String():string* return a string representation of the Cell.

###Implementation of the World.

World is a home for the matrix of the Cells. Each Cell is having X and Y coordinate in the world and Cell *name* plays no role in Game. World is convoluted or folded, "North" and "South" boundaries of the World are connected as well as "East" and "West". World defined as a structure with an interface functions.

First, World is having a *name:string* . Name of the World is  reserved for a User to use and play no role in algorithm. 

World do have a size with *xMax:int* and *yMax:int*. Interface functions *X():int* and *Y():int* are returning those values.

World do have an *ageMax:int*. This value is used to determine of what to do in case if Live Cell reaches that age. It will die. If Dead Cell reaches that Age, during the *Step():bool*, GoLife will call the function defined in *procreateFunc:func () bool*. If this function returns *true*, Cell will change from Dead to Live.

*immunityMax:int* bring an upper limit to a value assigned to a Cell immunity. Lower limit is 0.

*age:int* holds information on current age of the World. This value manifestoes in "now many times function Step() was called for the World"

*stepFunc: func()* is a reference to a function executed during each step.

*NotificationCh: chan Cell* is a channel for the Cell's. Every time when Cell changes status, GoLife sending it to this channel. Size of the channel defined by constant CHSIZE.

And now, few words about basic interface functions to the World:

* *Cell(int,int): (*Cell, error)*. This function returns a reference to a Cell defined by coordinates and error
* *GetCell(int,int): *Cell* Unlike previous function, this one returns a reference to a Cell or nil.
* *Step():* This function calculates the next step for the World, by calculating Step():bool for each Cell in the World.
* *Print():* This debug function display printable representation of the World on STDOUT.

Two group of interface functions I would like to discuss separately. First group, represented by function *Procreate(func ():bool):* This function set the function to the world, that called in determination, shall the Dead Cell procreate Life. If function returns true, then Cell will change status from Dead to Live. Otherwise NOOP.

Second group, controls if the World, permits to the Cells recovery from unfavorable conditions. By default, it will not. If you call *ImmunityRecovery():*, then recovery will be permitted beginning next step. If you call *NoImmunityRecovery():*, then, it will not.

##Use of the module

The use of the [github.com/vulogov/GoLife](https://github.com/vulogov/GoLife) module is very simple. First, you have to create a new World by calling package function *GoLife.NewWorld(string,int,int,int,int): *World*. This function will return a reference to the created World.

* first parameter is a string with a name of the world
* second and third, defines the x and y size of the World
* fourth, defined a maximum Age
* fifth, will set the maximum immunity threshold.

Example:

```golang
world := GoLife.NewWorld("world", 5, 5, 120, 10)
```
This command, will create World with 25 cells organized in 5x5. Maximum age will be 120, upper immunity threshold will be 10.

By default, life procreation is disabled. You have to define a function, which will control procreation. Let's define a function, which will generate a random number between 1 and 10 and permits procreation if this number is 0. Example:

```golang
world.Procreate(func() bool {
    if rand.Intn(10) == 0 {
      return true
    }
    return false
})
```
You can define this function ether inline, or import it from some other module.

Next, you better set some initial Cells to Live. Otherwise, you will be waiting for Procreation and if you do not set the Procreation function, your World will be desolate forever. Example:

```golang
world.ToLife(4,0)
world.ToLife(4,1)
world.ToLife(4,2)
world.ToLife(10,10)
```
Note, if you will try to operate with Cells outside of the World boundaries, NOOP will happens.

And now, when everything is set, let's loop our world through the steps and see the Life evolving. You have to call Step(): function for the World and read information about changed Cells from the *World.NotificationCh: chan Cell* attribute. Example:

```golang
for {
    world.Print()
    world.Step()
    if len(world.NotificationCh) > 0 {
      fmt.Printf("World is changing on step [%v]\n", 
             world.Age())
      for len(world.NotificationCh) > 0 {
        cell := <- world.NotificationCh
        fmt.Println(cell.String())
      }
    }
}
```
If everything is fine, you can enjoy watching the "Game of Life"


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jmqtbkyviivy8pwopje8.png)


##Conclusion

This very simple module, will permit you to bring a power of modified Life algorithm into your application. Bring your application to Life and spread the joy. Hope, use of [github.com/vulogov/GoLife](https://github.com/vulogov/GoLife) will be fun and enjoyable. If you feel, that you can improve the code, author accepts pull requests. Report bugs, and be good !