---
title: "Implementing Conway's Game of Life in Go⚡"
date: 2022-03-17
meta:
  title: Implementing Conway's Game of Life in Go⚡
  description: "My first ever project in Go. I'm implementing Conway's Game of Life in Go."
---

# {attributes.title}

{attributes.date.toDateString()}

![demo](https://github.com/nexxeln/go-gol/raw/main/images/demo.gif?raw=true)

I recently started learning Go and I absolutely love it. I think implementing Conway's Game of Life in a language is like a more sophisticated 'Hello World' program. Its pretty easy to do it and you learn a lot of stuff about that language. So that's what I did.

## Walk-through

So first let's initialize a Go project:

```bash
go mod init github.com/nexxeln/go-gol
```

Now make a `gol.go` file. This is where all our code will go.

```go
package main

import (
	"image/color"
	"log"
	"math/rand"

	"github.com/hajimehoshi/ebiten"
)
```

So we start by declaring this as the main package and importing the tools we need. The last one called `ebiten` is a very simple 2-D engine written in Go, and we import it straight from GitHub which is pretty cool.

```go
const scale int = 2
const width = 300
const height = 300

var blue color.Color = color.RGBA{69, 145, 196, 255}
var yellow color.Color = color.RGBA{255, 230, 120, 255}
var grid [width][height]uint8 = [width][height]uint8{}
var buffer [width][height]uint8 = [width][height]uint8{}
var count int = 0
```

Here we have declared some global variables. The `scale` is the density of the pixels. `width` and `height` are the width and height of the window. Next we declare some colors namely blue and yellow. The `grid` is where everything is going to be displayed and the `buffer` is the next iteration of the `grid`.

```go
func update() error {
	for x := 1; x < width-1; x++ {
		for y := 1; y < height-1; y++ {
			buffer[x][y] = 0
			n := grid[x-1][y-1] + grid[x-1][y+0] + grid[x-1][y+1] + grid[x+0][y-1] + grid[x+0][y+1] + grid[x+1][y-1] + grid[x+1][y+0] + grid[x+1][y+1]

			if grid[x][y] == 0 && n == 3 {
				buffer[x][y] = 1
			} else if n < 2 || n > 3 {
				buffer[x][y] = 0
			} else {
				buffer[x][y] = grid[x][y]
			}
		}
	}

	temp := buffer
	buffer = grid
	grid = temp
	return nil
}
```

This is the update function. Here we first get all the neighbors of the cell and store it in `n`. Next we check if the cells around it are dead, if yes we make it alive. If there's overpopulation or under population we make it dead, otherwise we just copy it to the next iteration. After that we just return `nil`.

```go
func display(window *ebiten.Image) {
	window.Fill(blue)

	for x := 0; x < width; x++ {
		for y := 0; y < height; y++ {
			for i := 0; i < scale; i++ {
				for j := 0; j < scale; j++ {
					if grid[x][y] == 1 {
						window.Set(x*scale+i, y*scale+j, yellow)
					}
				}
			}
		}
	}
}
```

This is the display function which is going to render it on the screen. This is where `ebiten` comes in. We start by defining `window` as an `ebiten.Image` and fill it with a nice blue color. Next for every pixel we're going to set that pixel as yellow.

```go
func frame(window *ebiten.Image) error {
	count++
	var err error = nil
	if count == 20 {
		err = update()
		count = 0
	}
	if !ebiten.IsDrawingSkipped() {
		display(window)
	}

	return err
}
```

This is the frame function. First we increment the `count` variable, and once it reaches 20 we're going to call the `update` function and reset the `count` variable. We also check if ebiten is not going to skip the rendering phase, then we're just going to call the `display` function and render it to the screen.

We're almost finished, let's set up our main function.

```go
func main() {
	for x := 1; x < width-1; x++ {
		for y := 1; y < height-1; y++ {
			if rand.Float32() < 0.5 {
				grid[x][y] = 1
			}
		}
	}

	if err := ebiten.Run(frame, width, height, 2, "Game of Life"); err != nil {
		log.Fatal(err)
	}
}
```

So we start off by setting up the grid and randomly populating it with cells using `rand.Float32()`. Next we use `ebiten.Run` to run the program with the name "Game of Life". If `ebiten.Run` returns an error we're just going to log it to the terminal. This is reminiscent of pattern matching in Rust.

Well that's pretty much it! Now just open up the terminal and run the program:

```bash
go run ./main.go
```

All the code can be found [here](https://github.com/nexxeln/go-gol).

This was my first blog ever, so please tell me if I did something wrong. If you read till here you're very cool. Okay bye!
