Markus Hutnik




The Game of Life, Go, and ANSI Escape Codes

Intro

Game of life is an example of cellular automata where a set of simple rules creates complexity. The main idea is that we start with a two-dimensional grid of "cells". At each timestep, each cell either survives, dies or becomes alive depending on the state of the neighboring cells. Each cell is evaluated using the following set of rules:

Out of these simple rules, very complex patterns can form. One intersting thing about the game of life is that it is also Turing Complete. Formally, this means that the game of life can be used to simulate any Turing Machine. Informally, this means that for any problem in which it is possible to solve it computationally, the solution can be encoded in the game of life.

game of life

The code for this project can be found in GitHub.




Why

I think the game of life is really interesting and it's fun to experiment with. In the past, I've written game of life in JavaScript (as a website) and Python (as a desktop app). Since I've been learning Go recently, I thought it would be fun to implement the game of life as a terminal-based program using Go. I wanted to write a program where I could just run a command and have game of life run in my terminal.




ANSI Escape Codes in Go

Using ANSI escape codes in Go is pretty straight forward. It's not something specific to Go. Like using ANSI escape codes in other languages, they just need to be included in print statements. In Go, they can be included in fmt.Println(), fmt.Print() or fmt.Printf() statements. For example, if I want to move the cursor up one line, I could use the following print statement:

fmt.Printf("\033[1A")



Implementation

Since this program would run in the terminal, I knew there would be very little coding for the UI. All I had to do was print all the cells to standard output at each timestep. Rather than using a library that could handle animation in the terminal, I figured the simplest solution would be to use ANSI escape codes. ANSI escape codes let you do a lot of cool things in the terminal like change the color/style of text, move the cursor around, clear lines of text and clear the entire screen.

For my program, I wanted the grid to print in the same place at each timestep so it looked animated. To do this, I moved the cursor back to the top left corner of the terminal each time I printed the grid. Then I would clear each line and reprint it using the following ANSI escape codes:

At first, I used \033[2J to clear the entire screen before printing the grid, but this caused a very slight delay between clearing the screen and printing the grid which made it look like the grid was flashing at each time step. Instead, I decided to just clear each line one at a time right before reprinting it and it made the "animation" look a lot smoother.

Aside from moving the cursor around and clearing text, I also used ANSI escape codes to add color to the output. For "alive" cells, I wanted them to display as red boxes. To do this, I would print a space if the cell was alive. Before printing the space though, I would use \033[0;41m. In this escape code, 0 is the foreground color. 0 also means reset, since I was just printing a space for alive cells, I didn't care about the foreground color. 41 sets the background color to red. The "m" indicates that these arguments should be applied to the style of the text. After printing an alive cell, I would use the code \033[0m to reset formatting so that dead cells (represented by a ".") would print normally.

this is another test

The ANSI escape codes were only used for formatting the output. The rest of the code for implementing the game of life is actually pretty simple. I represented the grid of cells as a 50 x 50 2d array of booleans (true is an alive cell, false is a dead cell). Then for each timestep (75 ms), I would evaluate the game of life rules and display the updated grid. Below is the code for evaluating the rules. Notice that I worked with a copy of the grid when evaluating the rules. This is because the next state of each cell needs to be determined based on the current state of the grid.

rules code

Each time the program is run, it randomizes the grid. I plan on also adding command line arguments so the program can accept a text file with the initial state.




Interesting Patterns

Note: my JavaScript implementation of the game of life is an easy way to play around with some of these patterns because it lets you draw on the grid.

Walker
This pattern repeats itself over time and appears to "walk" across the grid.

Initial state

walker

Effect

walker

10 Across
This is another pattern that loops and goes on forever.

Initial state

10 across

Effect

10 across

Explosion
This one does an interesting animation and results in a final state where each cell is satisfied and no longer changes. This means that each alive cell has two or three neighbors and no dead cells have exactly three neighbors.

Initial state

explosion

Effect

explosion

Pulsar
Another looping pattern. Flips between two states.

Initial state

pulsar

Effect

pulsar