Python Project: Guessing Game
Tags: beginners, tutorial, python, programming
Published: 2021-01-04 14:09:54

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 on this list:

- [if **name** == ‘**main**’ in Python](https://renanmf.com/if-__name__-__main__-python/)
- [How to generate a random value between two integers in Python](https://renanmf.com/generate-random-value-between-two-integers-python/)
- [Conditionals in Python](https://renanmf.com/conditionals-python/)
- [Functions in Python](https://renanmf.com/functions-python/)
- [`while` Loops in Python](https://renanmf.com/while-loops-python/)
- [`for` Loops in Python](https://renanmf.com/for-loops-python/)
- [String Interpolation with f-strings in Python](https://renanmf.com/string-interpolation-f-strings-python/)
- [User input in the command line in Python](https://renanmf.com/user-input-command-line-python/)
- [File Handling in Python](https://renanmf.com/file-handling-in-python/)
- [Handling Exceptions in Python](https://renanmf.com/handling-exceptions-python/)

## The Game

My suggestion is to open a text editor like [VSCode](https://code.visualstudio.com/), 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

```python
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!