Python Project: Guessing Game

This numbers guessing game is a simple game that allows you to practice many of the fundamentals of the Python language.

It is a great Python project for beginners and in this article you will find not only the source code, but also an explanation of how it works.

The game works like this:

  • You choose a level: 1 (25 chances), 2 (15 chances), 3 (5 chances)
  • The game will randomly pick a number from 1 to 1000
  • In every turn, you pick a number
  • The game will always tell you if your guess was lower or higher than the right number
  • You win if you guess the right number before you run out of chances
  • The game saves the highest score in a file named "score.txt".

Prerequisites

Although simple, this game involves many basic programming skills, and if you have any trouble following this code, don’t worry, there is an article for every single thing you should know right here on this blog:

The Game

My suggestion is to open a text editor like VSCode, copy and paste the code, or open this article in another browser window, and put it side by side with this window, this way you can read the explanation while following along with the code.

The code starts at the bottom, on the main block.

Choose a level: choose_level() function

It calls the function choose_level() on the main block and goes to the beginning of the code where the actual function choose_level() is and where you pick a level and get the number of chances accordingly.

The input() function is inside a while loop that only breaks if you pick a valid integer, otherwise, it will catch the error with the try/except block and print "Invalid choice", restarting the while loop so the user can choose a level again.

If the input is valid, but not 1 or 2 or 3, the if block will print "Not a valid level." and restart the loop using continue so the user can choose a level again.

If the input is valid and either 1 or 2 or 3, the program moves on.

The core of the Game: play_game(chances) function

Then the play_game(chances) function is called on the main block with the number of chances returned from choose_level() as an argument and the program goes to the implementation of play_game(chances).

Initializing the game

play_game(chances) starts by picking a random number from 1 to 1000 and by initializing the number of points to 9999.

The for loop uses the range(1, chances + 1) function giving a turn starting at 1 and going up until the number of chances you chose based on the difficulty level.

Note that range() does not include the number of the second argument, meaning that if you have 25 chances, it will only go until 24, that’s why we have to make "chances + 1".

The code then uses f-strings to print your current turn and how many chances you have.

Receiving input from the player

Then you guess a number with the input() function inside a while loop.

Note the try/except that catches an exception in case the user tries a value that’s different from an int.

If the value is invalid, the except block catches the error, prints "Invalid guess." and the while loop restarts.

If you chose a valid value but it isn’t between 1 and 1000, the if block will be triggered, print a message, and use continue to restart the loop.

If you choose a valid number that is between 1 and 1000, the break command will be triggered, breaking out the while loop, and the program then proceeds to check if your guess matches the right number on if guess == number:.

Checking your guess

The if\else block to check the guess against the right number goes two ways.

If the user nails it, the code will print the message with the score and call save_highest_score(points) to save the score on a file (I will explain save_highest_score(points) later).

If the user doesn’t guess the right number, it will go to the else block.

If the number is higher, the game prints "Your guess was too high, try a lower number.", if it is lower the game prints "Your guess was too low, try a higher number.".

The program then calls the function calculate_score(points, number, guess) (I will also explain this one later) to calculate your current score based on how many times you guessed wrong.

You always start the game with 9999 and then lose points every turn you guess wrong.

When you run out of chances and wasn’t still able to guess the number, the program goes to if turn == chances: where it checks if you exhausted the number of chances, and if you did, it prints "You ran out of chances!" and gives you the answer.

Finally, the game prints "Game Over!".

Calculating the Score: calculate_score(points, number, guess) function

Let’s understand calculate_score(points, number, guess).

The function calculate_score(points, number, guess) takes as arguments the current points the player has, the number they are trying to guess, and their current guess.

The code subtracts the right number from guess, and then we have a lost_points that is then subtracted from points.

Notice the use of the abs() built-in function, it returns the absolute value of a number.

The absolute value of a number is the value without considering its sign. So both -790 and 790 become 790.

This is important because if the right number is 200 and we guess 1, lost_points will be 199 which is alright, but if we guess 990, lost_points will be -790, which will increase the total number of points instead of decreasing it due to the code doing subtraction with a negative number.

To see this in action, try removing abs() from lost_points = abs(number - guess) so it will look like this lost_points = number - guess.

Saving the Final Score: save_highest_score(score) function

Finally, let’s analyze what save_highest_score(score) does.

It opens the file "score.txt" to read the highest score recorded in the game.

If there is no such file, the except block prints the message "There was no champion" since there is no previous score to compare.

If there is a file and it is not empty, the variable record stores the highest score.

Then we check if the current player’s score is higher than the previous one.

If it is, the program prints "You are the new champion!" and saves the new record on "score.txt".

If the current score is not higher than the one stored in the file the program prints "Try again to beat the champion!".

The Code

import random

def choose_level():
    print("How hard do you want the game to be?")
    print("1 - Easy - 25 chances to try")
    print("2 - Medium - 15 chances to try")
    print("3 - Hard - 5 chances to try")

    while True:
        try:
            level = int(input("Choose the difficulty level (1 or 2 or 3): "))
            if(level < 1 or level > 3):
                    print("Not a valid level.")
                    continue
            break
        except ValueError:
            print("Invalid choice.")

    if level == 1:
        chances = 25
    elif level == 2:
        chances = 15
    else:
        chances = 5

    return chances

def calculate_score(points, number, guess):
    lost_points = abs(number - guess)
    points = points - lost_points

    return points

def save_highest_score(score):
    record = 0

    try:
        with open("score.txt", "r") as score_file:
            record_line = score_file.read()
            if record_line:
                record = int(record_line)
                print(f"The record for this game is: {record} points.")
    except FileNotFoundError:
        print("There was no champion")

    if score > record:
        print("You are the new champion!")
        with open("score.txt", "w") as score_file:
            score_file.write(str(score))
    else:
        print("Try again to beat the champion!")

def play_game(chances):
    number = random.randint(1,1000)
    points = 9999

    for turn in range(1, chances + 1):
        print(f"-> Chance {turn} out of {chances}")

        while True:
            try:
                guess = int(input("Type a number between 1 and 1000: "))
                if(guess < 1 or guess > 1000):
                    print("Your guess must be between 1 and 1000!")
                    continue
                break
            except ValueError:
                print("Invalid guess.")

        if guess == number:
            print(f">> You nailed it! Final score: {points} <<")
            save_highest_score(points)
            break
        else:
            if guess > number:
                print("Your guess was too high, try a lower number.")
            elif guess < number:
                print("Your guess was too low, try a higher number.")

            points = calculate_score(points, number, guess)

        if turn == chances:
            print(">> You ran out of chances! <<")
            print(f"The right number is: {number}")

    print("Game Over!")

if __name__ == "__main__":
    print("###############################")
    print("Welcome to the Guessing game!")
    print("Guess the number from 1 to 1000")
    print("###############################")

    chances = choose_level()

    play_game(chances)

Testing the Game

The trick to winning in this kind of game is to divide the numbers in half when guessing, this way you eliminate 50% of the numbers in every turn, making your space of possibilities smaller quickly.

Let’s say the game starts with the random number 616.

Since this game goes from 1 to 1000, the logical first guess is 500.

Then the game will tell you guessed too low, so you know the right number is between 500 and 1000.

Then you try 750, the number in the middle of 500 and 1000.

The game will say you guessed too high, now you know the right answer is between 500 and 750.

You keep doing this until you either nail it or run out of chances.

To run the game, copy and paste the code in a file with any name, I chose the name "guessing_game.py", and then run:

python guessing_game.py

Or, depending on your Python installation:

python3 guessing_game.py

Here is a sample output of when you beat the game:

###############################
Welcome to the Guessing game!
Guess the number from 1 to 1000
###############################
How hard do you want the game to be?
1 - Easy - 25 chances to try
2 - Medium - 15 chances to try
3 - Hard - 5 chances to try
Choose the difficulty level (1 or 2 or 3): 1
-> Chance 1 out of 25
Type a number between 1 and 1000: 500
Your guess was too high, try a lower number.
-> Chance 2 out of 25
Type a number between 1 and 1000: 250
Your guess was too low, try a higher number.
-> Chance 3 out of 25
Type a number between 1 and 1000: 375
Your guess was too high, try a lower number.
-> Chance 4 out of 25
Type a number between 1 and 1000: 312
Your guess was too high, try a lower number.
-> Chance 5 out of 25
Type a number between 1 and 1000: 281
Your guess was too low, try a higher number.
-> Chance 6 out of 25
Type a number between 1 and 1000: 296
Your guess was too low, try a higher number.
-> Chance 7 out of 25
Type a number between 1 and 1000: 304
Your guess was too high, try a lower number.
-> Chance 8 out of 25
Type a number between 1 and 1000: 300
Your guess was too high, try a lower number.
-> Chance 9 out of 25
Type a number between 1 and 1000: 298
>> You nailed it! Final score: 9631 <<
There was no champion
You are the new champion!
Game Over!

Here is a sample output of when you lose:

###############################
Welcome to the Guessing game!
Guess the number from 1 to 1000
###############################
How hard do you want the game to be?
1 - Easy - 25 chances to try
2 - Medium - 15 chances to try
3 - Hard - 5 chances to try
Choose the difficulty level (1 or 2 or 3): 3
-> Chance 1 out of 5
Type a number between 1 and 1000: 4
Yout guess was too low, try a higher number.
-> Chance 2 out of 5
Type a number between 1 and 1000: 500
Your guess was too high, try a lower number.
-> Chance 3 out of 5
Type a number between 1 and 1000: 250
Yout guess was too low, try a higher number.
-> Chance 4 out of 5
Type a number between 1 and 1000: 23
Yout guess was too low, try a higher number.
-> Chance 5 out of 5
Type a number between 1 and 1000: 2
Your guess was too low, try a higher number.
>> You ran out of chances! <<
The right number is: 289
Game Over!

If you want to truly understand what is going on in this code, the best thing you can is to modify it and see what happens.

Try to change the messages in the print() functions, change the number of chances for each level, come up with a different approach to calculate the score on calculate_score(points, number, guess), etc.

There are many changes you can do to make this game even better!