Information Technology 10A

An Introduction to Games Programming in Go

Prof G-J van Rooyen

Overview

This module is intended to give the student a formal introduction to Go: a mainstream high-level programming language with broad application. The goal of the module is to develop a rudimentary 2-dimensional computer game. To reach this outcome, the student will have to master concepts like:

Setting things up

We start by installing all the prerequisite software, and testing the build pipeline with a simple program.

Ensure that the following are installed:

  1. Go
  2. VSCode
  3. The Go extension for VSCode
  1. Now create a file called welcome.go in a new directory (e.g. it10a\welcome.go) and type in the following:
package main

import "fmt"

func main() {
    fmt.Println()
    fmt.Println("Welcome to Great Old Escape")
    fmt.Println("Copyright (c) 2025 by Andus van Rooyen")
    fmt.Println()
}

(You’re welcome to make the welcome message say anything you want. Note that fmt.Println() without anything between the brackets leaves an ampty line.)

Press Ctrl-S to save the file. Now go to the “Terminal” tab in the bottom VSCode window. Note that you can drag the window to resize it. Type ls and it should show you the contents of the directory. If you don’t see welcome.go listed when typing ls, you’re probably not in the directory where you saved the project. If you hover over the welcome.go tab in VSCode, it will pop up the path where it is saved. Use cd in the terminal to go to the project directory. Remember that you can type cd .. to go up to the parent directory.

Type go run welcome.go to run your program, and check that you see the welcome message in the terminal.

Running your program

Type the following command in the terminal to run it:

go run welcome.go

It should display the welcome text. Try changing the text in the program, save it again (Ctrl-S) and run the program again. You should see the change in the output.

You can also build a program to create an executable file: this is a compiled program that only the computer can understand, but that is used to run the program. Now is the time to introduce some new terms:

Build an executable file for your program by typing to following command:

go build welcome.go

If you now type ls in the terminal, you should see a new file: welcome.exe. This is an executable file. On Windows, the .exe filename extension indicates that it is executable.

You can run it by typing .\welcome.exe, which should show the same output as before.

An executable file like welcome.exe is easy to distribute to other people, who do not need Go installed on their computers.

Understanding the program

In this course, we’ll often make use of Claude, an AI chatbot that is particularly good at helping with programming.

Go to https://claude.ai/ and use your Google account or email to sign up. Then go to your program (welcome.go) in VSCode, and type Ctrl-A and then Ctrl-C to copy all of it. Then go to the Claude chat and type the following (use Shift-Enter to create new lines without submitting the question yet):

Please explain the following Go code to me:

```

Note that last line: It should be three backticks in a row: That’s the character most likely somewhere on the top left of your keyboard, that looks a bit like `the opening quote in this part of the sentence’.

Once you press Shift-Enter after the three backticks – this indicates a source code block – Claude should open up a field where you can paste your source code. Press Ctrl-V to do so. Then press Enter to send the message to Claude.

Claude should now give you a line-by-line explanation of the program. Please feel free to use Claude to help you understand any of the course material, but don’t ask it to write code for you. Even though it will comply, AI devs often make mistakes, and the purpose of this module is for YOU to build your programming muscles. There is no coding without understanding!

Carefully review Claude’s explanation of the program, and ask him any questions on anything that is unclear. Your course instructor will also be able to help during tutorial sessions.

Let’s chat

Next, we want to modify the program so that it asks the user for a character name, and then greet the user using that name:

Welcome to the Great Old Escape
Copyright (c) 2025 by Andus van Rooyen

What is your character's name? Erandir
Welcome to the game, Erandir!

To do this, you will use the following library functions:

Variables

We need to be able to store the character’s name somewhere, so that we can display it again later. Values that aren’t known at compile time (i.e. when we write the program source code and compile it with go run or go build) can be stored in variables. You may remember variables from when you studied the graphical programming language Scratch.

Now is a good time do some reading about fundamental concepts. Study the following sections from Go By Example:

  1. Modify your program by declaring a string variable called name, and passing it to the fmt.Scanln() Although fmt.Scanln() is quick and simple to use here, it’s not a great way to read user input in general. For one thing, it stops reading at any whitespace, whether it’s a space or a newline (Enter). So if you type “Severus Snape” as name, it will just save “Severus” – which may lead to a rather irate professor when you later greet him on a first-name basis. We will look at more advanced input/output (I/O) techniques later in the module.

    function to store what the user typed: The &name syntax may seem weird at first. We’ll go into it in more detail at a later stage (so don’t worry too much about it now), but when you pass a variable like name to a function, you can give it the value of name, e.g. foo(name), or you can tell it where the name variable lives in the computer’s memory – this is called the address of name. fmt.Scanln(&name) can be read as, “Hey, Scanln, here’s an address where a variable named name stores a string. Please read some input from the user and store it at name’s address”. So you can think of “&name” to read “the address of name”. We say that we can pass a variable to a function by name, e.g. foo(name) or by reference, e.g. foo(&name).

fmt.Scanln(&name)

Operations

As you saw in the Values section in Go By Example, Go can perform various operations on values using operators like +, -, *, and %. The operators behave differently depending on the types of the values that they operate on (its operands). For example, 3 + 5 will produce a value of 8, whereas "foo" + "bar" would produce the string "foobar" – this is called string concatenation.

  1. Modify your program so that it asks for the character’s name, and then prints Welcome to the game, <name>!, where <name> is the string that the user entered.

Stats and modifiers

Next, let’s modify the program so that it creates a random Strength ability score for the character, and print it out with the modifier for that score, e.g.

Welcome to the Great Old Escape
Copyright (c) 2025 by Andus van Rooyen

What is your character's name? Erandir
Welcome to the game, Erandir!

Your strength is 14 (+2)

To achieve this, you’ll need to:

  1. Declare two variables of type int (integers, or whole numbers) named strength and strength_mod. Note that type int can be negative as well.
  2. Assign a random value from 3 to 18 to strength.
  3. Calculate the strength modifier and assign it to strength_mod.
  4. Print out a formatted string composed of a mix of strings and numbers.

Random numbers and string formatting

Study the following before attempting your solution:

The special sequence \n in a string starts a new line.

If/Else

To calculate the modifier for an attribute that is 10 or higher, you can simply use integer division: For example, for a strength of 11, (11 - 10) / 2 would evaluate to 0, which is the corrrect modifier. Verify that (12 - 10) / 2 evaluates to a modifier of +1.

Negative modifiers are a bit trickier! Suppose a character has a strength of 9; the rules require that the strength modifier is then -1. However, (9 - 10) / 2 evaluates to 0! This is because integer division always rounds towards zero. It “rounds down” for positive values, but it “rounds up” for negative values.

One way to work around this is to check whether the attribute (e.g. strength) is 10 or higher, or not, and then use a slightly different calculation for the two cases. For this you need an if statement with an else branch.

Read the following section from Go By Example:

Instructions

  1. Modify your program to calculate a random strength value, and to print the strength attribute and its modifier as shown in the example above.

If you run your program multiple times, it should produce different random strength values.

Functions

Your program now calculates the modifier for the strength attribute, but you would need to perform the same calculation for any other attribute: dexterity, constitution, intelligence, or whatever attributes you decide to use in your game. It would be cumbersome to type the same calculation over and over again. Also, if you discover a mistake in the calculation, or decide to calculate it in a different way, you will need to fix it everywhere.

A function is a way to define a certain operation once, so that you can use it repeatedly in many places. Read the following section from Go By Example:

  1. Create a Modifier() function that will return the correct modifier for any attribute value passed to it. Then use the Modifier() function in your main() function to calculate the strength attribute’s modifier and display it.

The function will need the following parameter and return type (we call this the function’s signature):

func Modifier(stat int) int

This means that your function will take one parameter, the value of an integer attribute like strength or intelligence. It will then return an integer, i.e. the value of the modifier.