Build an interactive guessing game with Golang

Codixir C
5 min readApr 13, 2019

The objective of this article is to build a small program that generates a random integer (which will be kept as a secret from the user), and prompts them to enter numbers (guesses) on the terminal (command line) until they enter a number that is an exact match of the secret integer.

What we need

The following packages will help us to accomplish our task:

- bufio — To capture user input from the terminal
- os — The os.Stdin field will be used as in io reader that gets passed into bufio
- math/rand — To generate the random integer
- log — To exit os on fatal error
- fmt — To print strings on the terminal
- strconv — To convert a string entry to integer
- strings — to Trim the user’s entry

Set up

To use the new Go modules feature, ensure you have at least Go 1.11 installed on your system. You can verify the version of Go you have with this command on your terminal:

go version

Create a directory anywhere on your system (it can be outside of your GOPATH) and cd into it just as below:

mkdir guessing-game && cd guessing-game

Once inside the directory enter the following command to initialize Go modules

go mod init guessing-game

This should create a new file called go.mod inside your guessing-game directory.

Now, create a main.go file inside the directory

touch main.go

Your directory structure should now look like the following:

- /guessing-game

- main.go
- go.mod

Implementation

Generate the random integer


import (
"fmt"
"math/rand"
)
var attempts []intfunc main() {
min := 1
max := 10
secret := rand.Intn(max-min) + min

fmt.Println(secret)
}

The above code, generates a random integer that is between 1 and 100.
You can see the Intn method of the rand package is passed the difference between the max and min and have the min added to the value it returns.

Not to forget, we have also created a global variable called attempts that is a slice of integers. This slice is needed to keep track of the number of attempts the user has made. On every attempt, we will append the integer to the attempts slice and at the end when the user correctly guesses the secret integer, we will simply get the length of the slice len(attempts) and notify the user with the following formatted message:

message := fmt.Sprintf(“Congrats!!!, You got the number after %d attempts!!!\n”, len(attempts))

Check your implementation

Save the above, open your terminal and build and run the program with the following command:

go build && ./guessing-game

The command is supposed to print a secret integer that is between the min and max values you provided to rand.Intn().

If you drill into the directory of your program, you will find an additional file that was not there before. This is the bin file created by the go build command you just entered on the terminal.

Interact with the terminal

Now you can utilize the bufio package to capture the text the user enters on the terminal.

func main() {
//...
reader := bufio.NewReader(os.Stdin)
fmt.Println("Enter an integer between 1 and 100")

for {
entry, err := reader.ReadString('\n')
if err != nil {
log.Fatal(err)
}
line := strings.Fields(entry)[0]
num, err := strconv.Atoi(line)
attempts = append(attempts, num)
}
//...
}

The NewReader() method of bufio takes an io reader paramter. In this case os.Stdin is passed as a param and the method returns a reader struct, which has a method called ReadString that takes a delimiter (the new line character \n” in this case), which in turn returns two values (a string and an error) which we are capturing in the variables entry and err. But before that we have a simple print statement, that prompts the user to enter an integer.

The for loop is a strange looking loop if you are coming from another programming language. In theory it is similar to the while loops found in most other languages. In this case our for loop runs forever until we decide to terminate the program. Later on we will add a break; statement that breaks us out of the loop. But the code inside this loop will continue to be executed as long as the program is running and the user is entering values on the terminal.

Following our invocation of ReadString(‘\n’), we check if there is an error, and if that is the case, we invoke the Fatal method on the log package to exit the process. But if there is no error, we extract the first entry using the Fields method the strings package. The Fields method takes string (what the user enters on the terminal) and splits the string into a slice of strings. We extract the first element of the slice with [0], and assign the value to the line variable.

Now, since the entry on the terminal is always of the type string, we need to convert it to integer, so we can compare it the value in our secret variable. To do that we will utilize the Atoi method of the strconv package. You can see we passed line into Atoi() above and assigned the returned values to num and err.

Compare the entry with the secret number

[code]for {
//...
if err != nil {
fmt.Println("Enter a number between 1 and 100.")
} else if num < 1 || num > 100 {
fmt.Println("Enter a number between 1 and 100.")
} else {
if secret-5 <= num && num < secret {
fmt.Println("You are extremely close from the left.")
} else if secret-10 <= num && num < secret-5 {
fmt.Println("You are very close from the left.")
} else if secret-20 <= num && num < secret-10 {
fmt.Println("You are somewhat close from the left.")
} else if num < secret-20 {
fmt.Println("You are way off from the left.") } else if secret+5 >= num && num > secret {
fmt.Println("You are extremely close from the right.")
} else if secret+10 >= num && num > secret+5 {
fmt.Println("You are very close from the right.")
} else if secret+20 >= num && num > secret+10 {
fmt.Println("You are somewhat close from the right.")
} else if num > secret+20 {
fmt.Println("You are way off from the right.")
} else if secret == num {
message := fmt.Sprintf("Congrats!!!, You got the number after %d attempts!!!\n", len(attempts))
fmt.Println(message)
break
}
}

Finally we are doing comparisons of the user’s entry with the secret integer. Feedback is provided based on how close the entry is to the secret number. For instance if the user enters a number that is between the target (secret integer) and the secret integer minus 5, we provide them with the feedback you are extremely close to from the left. If the number is less than the the previous range, the feedback gets changed as well.

On the user entering an exact match, a formatted string is created to congratulate the user and notify them on the number of attempts they had made before reaching the number.

Summary

We have been able to implement a small Go program that had access to the command line. Different packages were used for tasks such as generating a random number, reading command line entries, string to integer conversion and etc. The user’s entries were captured and compared with the secret integer and different proximity based feedbacks were printed on the terminal.

Source code: Github

Please subscribe to this blog to get more articles and tutorials on Golang.

You can checkout our other Golang courses on udemy:

--

--