Build a Snake Game Using Go
Play your way to learning Go — step-by-step
In this article, we are going to build together the classic game of Snake using Go. This is my first project in Go and what better opportunity to share my learning experience with you and hopefully help your journey to learning Go as well?
The full code for this project (separated into parts) is in this GitHub repo
The outline of this post is as follows:
- Part 1— Why Bother?
- Part 2— Setting up our environment
- Part 3— Implementing Snake in Go
- Part 3.1— A moving blob
- Part 3.2— A moving snake
- Part 3.3— Adding food and points
Part 1— Why Bother?
Why learn a new language? And why not just follow the official tutorial and call it a day?
- Learning a new language makes us better programmers. Every programming language has its set of strengths and features and opening up to languages we haven’t seen before can open us to new ideas and programming paradigms and also add another tool to our toolchain.
- What better way to learn than by games? I personally think it’s way more fun than following an instruction manual.
So why Go?
Go is a language created by Google, with version 1.0 being released to the public back in 2012. Since then Go has developed and gained major traction amongst developers. Go is notable for being fast and easy to learn with a strong focus on efficient concurrency (read about goroutines [2] for more info). I decided that such a popular and trending language deserves a bit of my attention, even if I’m not planning to use it for anything practical in the near future, and thus this tutorial was born!
Part 2— Setting up our environment
The installation part is relevant only for Linux. Note that it will install an older version of Go (1.13 as of writing this article) but it is sufficient for our project.
Installation: Install Go using the following command: sudo apt install golang-go
. After following through the installation, check that your system has installed Go by running go version
. Your output should look something like this: go version go1.13.8 linux/amd64
(depending on the version you installed). After this is done we can create our first project!
Creating a project: We will be using Visual Studio Code (vscode) as our IDE (you can still follow through using other IDEs). Create a new folder for our project called Snake and open up the IDE in this folder. If using vscode you should install the Go extension via the Extensions tab.

Open up the terminal (can be done directly in VS Code), type go mod init Snake
, and hit Enter.
This should create a new file go.mod
in your current directory (the Snake directory). If we were publishing this project as a module we would have replaced Snake
with a valid URL, such as our GitHub repository, but since this is just a toy project we don’t care about that.
Let’s just write a simple “Hello World” project to see that everything is up and running properly. Create a new file called main.go
in the Snake directory and type in the following code:
package mainimport "fmt"func main() { fmt.Println("Hello World!")}
In this code, we imported and used the standard fmt
package which deals with command line input and output. In the terminal run go run main.go
. You should see Hello World!
printed in your terminal and the program should exit. If this is done we are good to go to the next part — building a Snake game!
When you want to run a project consisting of several files (as in this game) — from the directory that contains your code run go run *.go
. What will happen is that your main function will run with awareness of the other files in the project (if you just run go run main.go
it will ignore all of the other files and break due to missing dependencies).
Part 3— Implementing Snake in Go
This implementation is inspired by and based on the Pong Go tutorial [3] created by Josh Aletto.
Part 3.1— A moving blob
In this first part, we will create a keyboard-controlled blob on the screen. We are starting with this because it is a relatively simple logic task and it will allow us to focus on the basics of the language and the terminal-based GUI framework we will be using — tcell
[4].
Part I will consist of three files —
main.go
will contain the UI loop which will listen for user input and update the relevant data structures accordingly. It will also initiate the subroutine ingame.go.
game.go
deals with the main game loop — updating the state of the different elements in the game and drawing them on the terminal screen.snake.go
handles the inner state of the snake object (currently just its speed and position)
Let’s view the files:
main.go
—
- In lines 11–18 we get the
screen
object fromtcell
and do some error handling when screen fetching fails. - In lines 23–33 we define our two objects, the
game
and theSnakeBody
and initialize them with some initial parameters. - In line 34 we run a
goroutine
which starts the main loop of thegame
in a different thread. We will view the game loop later. - In lines 35–53 we deal with user input. Either the user presses
ctrl+c
and then we exit the program, or the user presses one of the arrow keys and then we send the relevant signal to thegame.SnakeBody
object, to change the direction of movement.
game.go
—
- Lines 21–27 define the main game loop. At the start of each step we clear the screen, then we update the
snakeBody
location and draw it on the screen. After that, we performtime.Sleep
to hold the previous frame on the screen (otherwise the movement would be too fast for us to visually perceive). Finally, we draw the new frame onto the screen.
snake.go
—
- This file defines our snake object (currently just a blob) and deals with the changing of direction and the updating of the current location using the current speed. Notice that if the snake disappears into one edge of the screen we want it to reappear at the other edge, hence the complexity in lines 16–23.
The gameplay in this part should look like this:

Part 3.3— A moving snake
To implement a moving snake we will first need to define what being a “snake” means. In this context it means an entity consisting of several parts, where each part has its own X and Y coordinates. By noticing that the movement of the snake can be modelled using a queue we can implement this in a simple and elegant way, as shown in the following figure.

Most of our changes will occur in the file snake.go
where the queue logic will be implemented (Go doesn’t have built-in queues so we will implement them using slices). Some minor changes will also happen in main.go
and game.go
mainly to support the changes in the former.
main.go
—
- In lines 23–36 added an initialization to the
snakeParts
object which constitutes the initial building blocks of the snake.
game.go
—
- Added the
drawParts
function which will draw the snake’s parts onto the screen in each iteration of the game loop.
snake.go
—
- Added the
Update
function which implements the snake’s movement in a queue-like fashion. In each activation of this function a new head is enqueued (depending on the direction of the snake) and the tail’s end is dequeued.
The gameplay in this part should look like this:

Part 3.3— Adding food and points
In this part, we will add important logic to the game including:
- The ability to collect food and earn points
- Make the snake longer if it collected food
- Detecting collisions of the snake’s head with its body
- A “Game Over” screen, with the option to replay or to quit
Let’s discuss the changes required in each of the 3 files:
snake.go
—
- Lines 21–23: check if the
longerSnake
parameter was passed as true. If so, Don’t perform a dequeue on the snake’s body and thus make it one tile longer. - Added the
ResetPos
function for convenience (this function will be called frommain.go
)
game.go
—
- Added
drawText
function to draw text on the screen. Taken from another snake implementation using cell [5]. - Added
checkCollision
function which receives a List of parts and another part. For each part in the list of parts, it checks whether it collides with the other part. We use this function to check 1) whether the snakehead has collided with food and 2) whether the snakehead has collided with the snake body. - Added logic in the main loop (I will detail the less trivial additions):
1) lines 72–76: check for collision with food and update score if collision detected. Also, redraw food in a random location.
2) lines 86–88: Game Over screen. Notice that after displaying the score this subroutine will terminate (Inmain.go
the user will have an option to start another goroutine with a fresh game)
main.go
—
- Lines 43–47: These lines deal with the Game Over situation. If a game over is detected (using the
GameOver
bool ingame
), the user has an option to pressy
orn
and the game will either restart or terminate accordingly. We restart the game simply by initiating another goroutine.
The gameplay in this part should look like this:

And we’re done with the implementation! Your snake game is up and running and you can invite friends over for a tournament :)
Thoughts Ahead
I hope you had fun implementing Snake in Go, I know I did. I think goroutines are a super-cool feature, I don’t know other languages where it is that easy to perform parallelization. Although this game is fairly simple I still liked the queue implementation of movement as a small mental exercise. This experience will also shorten the learning curve if I ever have to use this language for anything practical, and it’s always good to have another tool under my belt.
If I had more time I would extend this game and add cool power-ups to my snakes such as particle-shooting abilities, speed changing, and other goodies. I would also add unit tests to make sure that nothing breaks after these feature additions.
Thanks for reading, see you next time!
References
[1] — Full project code: https://github.com/erap129/SnakeInGo
[2] —goroutines: https://golangbot.com/goroutines/
[3] — Pong go tutorial: https://earthly.dev/blog/pongo/
[4] — tcell Go package: https://github.com/gdamore/tcell
[5] — Another snake implementation using tcell
: https://github.com/liweiyi88/gosnakego