Build a game with Python

What is Python? A snake able to squeeze the life out of its prey? A reference to Monty Python’s Flying Circus? An easy-to-learn and use programming language? The answer is, all of the above. However, in our case, we’re concentrating on Python, the programming language.

A programming language is a list of instructions to make a computer do something for us. It can be as simple as “add 3 plus 4 (3 + 4) and display the result (7)”, or “add the shopping to the shopping list and notify me when I’m in the shop”.

In this introduction, we’ll concentrate on creating a delightful game, “Rock, Paper, Scissors” using Python to learn some of the basics.

Our Python interpreter interprets our instructions to our computers. It translates our instructions to something the computer understands, 0’s and 1’s.

Before we can instruct our computer on what to do for us, we need to prepare our development environment.

The approach we’re covering is:

  1. Setup our development environment: download and install our Integrated Development Environment or Code Editor, download and install Python.
  2. Our simplified development methodology: Plan -> Code and Test -> Document.
  3. Programming: coding the “Rock, Paper, Scissors” game.
  4. Summary

How to Install Python & Code Editor

Please view this YouTube video for details on how to download and install the components below:

When writing code, we can use any text editor or word processor. However, some are better suited for the job than others. Some good ones are Microsoft’s Visual Studio Code and JetBrains PyCharm. We’ll use Jetbrains PyCharm in this example.

  1. Download and install Python: Python Download.
  2. Download, install and configure JetBrains PyCharm: JetBrains PyCharm.

Simplified Development Methodology

Now that we have our development environment let’s code. Successful and stress-free programming requires planning about what to code (write) and how. A simplified approach to follow:

  • Plan
  • Code and Test
  • Document

Plan

First, we analyse the problem we’re trying to solve, breaking it down into smaller, more manageable components that we solve with code. Solving each smaller component means we solve the initial larger problem.

In the case of coding our “Rock, Paper, Scissors” application (game) we break it down into the following components:

  1. Two players, one is the computer, and the other is the user.
  2. Each player selects either “Rock”, or “Paper”, or “Scissors”.
  3. We compare the selections to see who’s won, or if it was a draw.
  4. We store the results (game result statistics).
  5. We start again or quit.

This makes it easy to code.

Code and Test

We write code for each sentence and test each piece of code to make sure it works as expected before moving on to the next piece. The tests we perform must test both correct and incorrect data and choices to make sure the application doesn’t break when our users use it.

Document

“All code is self-documenting.” – the Lazy Programmer.

Why do we document our code? We document our code to aid us, our colleagues, and future programmers, in understanding what we have done and why. Our code makes sense while we write it, though less so in a week or month or year from now. Code that no one understands gets left as nobody knows what it does or what it breaks if it’s removed. This leads to something we call technical debt and is a bit like leaving rubbish around as we’re not sure whether something important is hiding in the rubbish. Over time our rubbish heap grows and becomes unmanageable. That’s the way with undocumented code.

We will not have to document anything beyond what we have already written for this example, though we will add comments to our code as we write it.

Programming

Please view this YouTube video as a complement to this Blog for a complete walkthrough of the coding of this application, “Rock, Paper, Scissors”.

Now to the fun part!

We have our empty python file, eagerly awaiting our code (instructions).

Let’s start by providing ourselves with a little guidance, adding the comments from our plan to the code. All code comments in Python start with the character #.

# Two players, one the computer and the other the user.
# Each player selects either "Rock", or "Paper", or "Scissors". 
# We compare the selections to see who's won, or if it was a draw. 
# We store the results (game result statistics). 
# We start again or quit.

Our Python interpreter ignores comments like the ones above. They’re not translated to 0’s and 1’s for the computer to execute.

Solving Programming Problem 1: Computer Player

How do we let the computer play “Rock”, or “Paper”, or “Scissors”? We must find a way to get the computer to make a random choice. As luck would have it, Python provides such a function, or rather a library of functions called random, that we can use. To load the random library, we import it to use its list of functions. Think of the random library as our local library, and the random library functions as books in our local library.

import random

Next, we want the computer to use the random library to select “Rock”, or “Paper”, or “Scissors”, and to save the random choice in a variable. A variable is a place in the computer’s memory (called Random Access Memory) where we can store values, in this case, the computer’s random selection. Think of a variable as a note on a notebook written in pencil and erased once used.

We start off by testing that we can get a random integer (number) from 0 to 2. Why 0 to 2 and not 1 to 3? Computers and most programming languages start counting from 0 and not 1. Power on = 1, and power off = 0.

We use this as a pointer to a list containing “Rock”, “Paper”, and “Scissors” for the computer. In other words, we get a random number from 0 to 2 (0, 1, 2) that points to a list of 0 = “Rock”, 1 = “Paper”, and 2 = “Scissors”.

computer_rps = random.randint(0, 2)

To test whether this code works, we can wrap it into a print statement (function). This displays the results in the console.

print(computer_rps = random.randint(0, 2))

We run our program a couple of times to see that we get random results (0 or 1 or 2). Once done, we remove the print statement.

computer_rps = random.randint(0, 2)

What we have so far is:

import random
 
computer_rps = random.randint(0, 2)

Next, we create the list that we want to point to and place it on the line before our computer_rps variable. This way our Python interpreter has read the list, loaded it to memory, and understands what we’re referencing once we use our random integer (0 to 2) as a pointer. We’ll get an error message if we don’t declare (define) our list before we use it.

rps_list = ["rock '()'", "paper '[]'", "scissors 'db'"] is a variable (stored in memory) called rps_list that contains the list ["rock '()'", "paper '[]'", "scissors 'db'"]. In Python, a list is declared between [] and each list item is enclosed in "" if text and separated by a ,.

computer_rps = rps_list[computer_rps] uses the computer_rps variable (0 or 1 or 2) to point to the rps_list. 0 = “Rock”, 1 = “Paper”, and 2 = “Scissors”. The result is stored, overwriting the variable content in computer_rps with the pointer value (“Rock”, “Paper”, Scissors”).

import random
 
rps_list = ["rock '()'", "paper '[]'", "scissors 'db'"]
computer_rps = random.randint(0, 2)
computer_rps = rps_list[computer_rps]

We’re done with the first iteration for the computer for now. We’ll revisit this a little later when we tie it all together after having solved each programming problem.

We now have a working computer player. Simple!

Solving Programming Problem 2: Human Player (User)

How does the human player (user) talk to the computer, entering the “Rock”, “Paper”, and “Scissors” choice?

We, as humans, must enter our information using the keyboard to communicate our choice of “Rock”, “Paper”, “Scissors” to the application and computer. To this end, we need a prompt to ask us to enter our choice, save our choice, and handle incorrect entries.

player_rps = input("\nPlease enter 'r = rock' or 'p = paper' or 's = scissors' or q to quit: ").strip().lower()

player_rps is our user variable, our area in the computer’s memory (RAM) where we store our entry (input). input() is another function, one that expects an entry (input from the keyboard) typed by a user. To it we add a sentence (string) “\nPlease enter ‘r = rock’ or ‘p = paper’ or ‘s = scissors’ or q to quit: ” requesting input from the user/human player. To keep things simple, we’re asking for an ‘r’ for “Rock”, a ‘p’ for “Paper”, an ‘s’ for “Scissors”, and a ‘q’ to quit the program. 

It‘s prudent for us to add a variable declaration, setting the variable player_rps to empty, player_rps = "". The "" means an empty string.

What are the .strip().lower() doing to our input? Our computers require us to be exact in setting our expectations of what we want them to do. From our computers’ perspective, an ‘r’ and an ‘R’ are two different things. They have two different values. To make our program easier to code and understand, we make sure that the input is as simple as possible.

.strip() removes any whitespace that we may mistakenly add to our response.

.lower() converts all characters (text) to lowercase, meaning that when we check to see what the player has entered, all we need to do is check for ‘r’ and not ‘r’ and ‘R’ for “Rock.

To test our player logic (code) we run the application to ensure that our input works. To view the output, we add a print() function, in the same way we did for the computer player. This means that our code now looks like this:

import random
 
rps_list = ["rock '()'", "paper '[]'", "scissors 'db'"]
computer_rps = random.randint(0, 2)
computer_rps = rps_list[computer_rps]
player_rps = ""
 
player_rps = input("\nPlease enter 'r = rock' or 'p = paper' or 's = scissors' or q to quit: ").strip().lower()
 
print(player_rps)

We have the computer player, and we have the input from the human player. What’s next? What do we do with the input from the human player? How do we compare what the computer and human players have chosen?

To compare what the computer and human players have selected, we must compare “like-for-like”, and to this end, we must translate the human player’s input of ‘r’ to “rock”, ‘p’ to “paper”, and ‘s’ to “scissors”.

We could force the human player to enter “rock” or “paper” or “scissors” in full; however, a better way is to translate the characters to the full word before comparing the selections with the computer player’s selections.

This piece of code takes the human player’s input of either ‘r’ or ‘p’ or ‘s’ or ‘q’ or something invalid (not one of the above choices) and translates it to the full words, and we do this before we compare the values (player’s choices). For now, though, we’re simply testing the logic of the code, making sure that we’ve thought through it all and implemented it correctly.

    if player_rps == "r":
        player_rps = "rock"
    elif player_rps == "p":
        player_rps = "paper"
    elif player_rps == "s":
        player_rps = "scissors"
    elif player_rps == "q":
        exit(-1)
    else:
        print("Please try again!")

The ifelif, and else statements allow us to check each input before assigning the full word value to our variable.

if player_rps == "r": checks whether the human player entered an ‘r’, if that is the case then the value “rock” is assigned to the variable player_rps: player_rps = "rock". If the human player didn’t enter an ‘r’ the program moves on to the next statement to check the entered character, the elif player_rps == "p": which is an “else-if human player entered a ‘p'”. If a ‘p’ was entered the value “paper” is assigned to the variable player_rps: player_rps = "paper".

The same applies to the ‘s’, and ‘q’. However, when entering ‘q’ the program executes the exit(-1)statement that closes and exits the program. The -1 tells the program to provide an exit code of 255 that we can check if running the program in a script or from another program, though this is of no consequence to us now.

The final else statement is run if none of the characters entered by the human player matches any of the choices. This asks the human player to try again.

You’ve noticed the use of = and ==. What’s this all about? In a lot of programming languages, and Python is no exception, a single = is an assignment operator. It assigns the value to the right to the variable to the left of the =. The == is an equal sign, a comparison of the value or variable to the left compared to the value or variable to the left of the ==.

Something else you’ve noticed is the spacing of the code statements. Some of them are indented by four spaces! Why? In Python, statements at the same indentation level are a part of the same block of code. Other programming languages use curly braces ‘{}’ to tell the interpreter (programming language) that this is a block of code, for example:

{
    Code entered between these curly braces for the block of code
}

Our Integrated Development Environment (Editor) PyCharm is intelligent enough to aid us with this, though we need to be aware of this when coding longer and more complex programs. For now, it’s something worth taking note of, though not worry overly about.

We’re done with the first iteration for the human player for now. We’ll revisit this a little later when we tie it all together after having solved each programming problem.

Solving Programming Problem 3: Comparison (Who has won?)

We have the computer player’s choice of “rock”, “paper”, “scissors”, and we have the human player’s choice of “rock”, “paper”, “scissors. How do we compare these choices to see who has won?

In this snippet of code, we’re including comments that describe what each statement does. This is a good practice as it clarifies to other programmers what we are doing and why.

# Evaluations, draw or win or loss. Counters for statistics.
    if player_rps == computer_rps:                  # If both are equal (same choice), it's a draw.
        draws += 1                                  # Add 1 to draws for statistics.
        print(f"\33[97m\33[44m A draw! :-| You played {player_rps}, and the computer played {computer_rps}. \33[0m")
    elif [player_rps, computer_rps] in win_list:    # If player has a winning combination, it's a win.
        wins += 1                                   # Add 1 to wins for statistics.
        print(f"\33[97m\33[42m You won! :-) You played {player_rps}, and the computer played {computer_rps}. \33[0m")
    else:                                           # If neither a draw or a win, it's a loss.
        losses += 1                                 # Add 1 to losses for statistics.
        print(f"\33[97m\33[41m You lost! :-( You played {player_rps}, and the computer played {computer_rps}. \33[0m")

To make this work we reference the list rps_list = ["rock '()'", "paper '[]'", "scissors 'db'"].

We also need to create a new list to reference, a list of winning combinations. In our code, we add this win_list = [["rock '()'", "scissors 'db'"], ["paper '[]'", "rock '()'"], ["scissors 'db'", "paper '[]'"]]above rps_list = ["rock '()'", "paper '[]'", "scissors 'db'"]. How this is used we’ll see below, however, for now it gives us a list of the possible winning combinations:

  • ["rock '()'", "scissors 'db'"] –> “rock” beats “scissors”
  • ["paper '[]'", "rock '()'"] –> “paper” beats “rock”
  • ["scissors 'db'", "paper '[]'"] –> “scissors” beats “paper”

You’ve noticed that the ‘win_list’ looks a little different to the ‘rps_list’. The ‘win_list’ is a list of lists (a number of lists within a list). We do this as it makes it easier when we check for the winning combinations in the code below.

To save the game statistics for our “win”, “draw”, and “losses” counters, we need to declare these variables, which we do with draws = wins = losses = 0. This is a short-hand way of making all three variables equal to zero (0).

if player_rps == computer_rps: checks if the computer and human player have made the same selection, a draw. If that is the case, we do two things, draws += 1 adds 1 to our counter variable draws. It looks a little odd, += 1? This is code shorthand for “add one (1) to the variable draws” and could be written as draws = draws + 1. Add one (1) to the current value in the variable draws and assign it to our (same) variable draws. draws += 1 is a shorter and faster (lazier) way to write this piece of logic. The second piece print(f"\33[97m\33[44m A draw! :-| You played {player_rps}, and the computer played {computer_rps}. \33[0m")prints the result to the console (monitor) to tell the human player that we have a draw. Let’s break this down and simplify this a bit. print(f"A draw! :-| You played {player_rps}, and the computer played {computer_rps}.prints “A draw! 😐 You played {player_rps}, and the computer played {computer_rps}.” and if both players played “rock” will print A draw! :-| You played rock '()', and the computer played rock '()'..

Please note that the character combinations of \33[97m\33[44m and ending with \33[0m are known as ANSI (American National Standards Institute) escape codes and date back to the 1970s (yes, I’m that old). They give our console text colour. We use the colour blue for draws, red for losses, and green for wins.

elif [player_rps, computer_rps] in win_list: is another else-if statement, and in this case, checks whether we have a winning combination for the human player. How does this work? It compares the combination of the values in the two variables to the winning list of lists. For example, if the human player plays “rock” and the computer player plays “scissors” we get: elif [rock '()', scissors 'db'] in [["rock '()'", "scissors 'db'"], ["paper '[]'", "rock '()'"], ["scissors 'db'", "paper '[]'"]]:and there is a winning combination of “rock” beats “scissors”. The next statement, wins += 1 works in a similar way to the draws += 1 above. We add (increment) the value in the wins variable by one (1). The print statement, print(f"\33[97m\33[42m You won! :-) You played {player_rps}, and the computer played {computer_rps}. \33[0m")is similar to the print statement for the draw, though in this case, we have a win.

If we don’t have a draw and don’t have a win, we have lost, and the last statement adds one (1) to the variable losses, followed by the print statement that tells us that we’ve lost.

For now, we’re done with the comparison logic; however, we’ll return to improve upon this a little later.

Solving Programming Problem 4: Game Results (Statistics)

This piece of the programming logic of our code simply prints a recurring statement of our results when we play multiple times:

# Print the game statistics after each round.
    print(f"Game statistics for this round:\nPlayer => \33[97m\33[42m Wins: {wins} \33[0m, \33[97m\33[44m "
          f"Draws: {draws} \33[0m, \33[97m\33[41m Losses: {losses}. \33[0m")

Given our review of the previous code, we now understand what this snippet of code does. It prints the values of the three variables “wins” (our wins, the computer’s losses), “losses” (our losses, the computer’s wins), and “draws”.

Solving Programming Problem 5: Improving our Program with a While-Loop

At the moment, we can only play one game at a time, which is fairly pointless. We want to play multiple games in a row and see our game statistics improve as we beat the computer. How do we do this? We use a loop. In our case, a While-loop. Loops in any programming language allow us to run blocks of code for a number of iterations (a “for-loop”) or while a specific condition (check) is True (a “while-loop”).

We’re going to use a “while-loop”. We “wrap” our human player, comparison, and statistics code block in the “while-loop”. while True runs this loop as long as the statement is True, which in this case is forever. In some cases, this is bad, as it’s an infinite loop (never-ending) and will continue until we break or stop the program running. However, we have a “trick up our sleeves”. We have the ‘q’ for quit statement that allows the human player to exit the program. Please look at this piece of the logic:

    else:
        print("Please try again!")
        continue        # Continue to the start of the While-loop, skipping the next code block.

If we don’t enter a valid input (‘r’, ‘p’, ‘s’, ‘q’) the program asks us to please try again and goes back to the start of the while True statement as we don’t want to run the comparison nor the statistics code. It does this with the continue statement.

Our complete code, with in-line code comments to clarify what we’re doing and why:

# Importing 'random' library to use 'randint()' for the computer rock, paper, scissors choices.
import random
 
# 'win_list[]' contains the winning combinations for the player. Anything else is a loss or a draw if choices are equal.
# 'rps_list[]' contains the choices for the computer, based on the random number index of 0 to 2.
# 'player_rps' is the string variable for the player's choice.
# 'draws = wins = losses = 0', sets all three variables to the Integer 0. Used for game statistics.
win_list = [["rock '()'", "scissors 'db'"], ["paper '[]'", "rock '()'"], ["scissors 'db'", "paper '[]'"]]
rps_list = ["rock '()'", "paper '[]'", "scissors 'db'"]
player_rps = ""
draws = wins = losses = 0
 
# While-loop (While True:) continues until player selects 'q' to quit.
while True:
    computer_rps = random.randint(0, 2)     # Random number from 0 to 2, rps_list[] index.
    computer_rps = rps_list[computer_rps]   # Save "rock '()'" or "paper '[]'" or "scissors 'db'" string.
    # Ask for player input. Remove whitespaces 'strip()' and convert all entries to lower-case 'lower()'.
    player_rps = input("\nPlease enter 'r = rock' or 'p = paper' or 's = scissors' or q to quit: ").strip().lower()
    # Player choice is set to full string for later comparison with the computer's random choice.
    # 'q' for quit, printing end-of-game statistics.
    # Handles any incorrect entries, to 'continue' to the start of the While-loop, skipping the evaluations code block.
    if player_rps == "r":
        player_rps = rps_list[0]
    elif player_rps == "p":
        player_rps = rps_list[1]
    elif player_rps == "s":
        player_rps = rps_list[2]
    elif player_rps == "q":
        exit(-1)
    else:
        print("Please try again!")
        continue        # Continue to the start of the While-loop, skipping the next code block.
 
    # Evaluations, draw or win or loss. Counters for statistics.
    if player_rps == computer_rps:                  # If both are equal (same choice), it's a draw.
        draws += 1                                  # Add 1 to draws for statistics.
        print(f"\33[97m\33[44m A draw! :-| You played {player_rps}, and the computer played {computer_rps}. \33[0m")
    elif [player_rps, computer_rps] in win_list:    # If player has a winning combination, it's a win.
        wins += 1                                   # Add 1 to wins for statistics.
        print(f"\33[97m\33[42m You won! :-) You played {player_rps}, and the computer played {computer_rps}. \33[0m")
    else:                                           # If neither a draw or a win, it's a loss.
        losses += 1                                 # Add 1 to losses for statistics.
        print(f"\33[97m\33[41m You lost! :-( You played {player_rps}, and the computer played {computer_rps}. \33[0m")
 
    # Print the game statistics after each round.
    print(f"Game statistics for this round:\nPlayer => \33[97m\33[42m Wins: {wins} \33[0m, \33[97m\33[44m "
          f"Draws: {draws} \33[0m, \33[97m\33[41m Losses: {losses}. \33[0m")
A picture containing graphical user interface

Description automatically generated

Summary

We’ve created a delightful game of “Rock, Paper, Scissors” in the programming language Python using an Integrated Development Environment called PyCharm.

We now know what a programming language is and what we can do with it, code programs to do useful and fun things for us.

We covered the setup of our development environment and the approach we take to programming:

  1. Download and install Python.
  2. Download and install our Integrated Development Environment (JetBrains PyCharm)
  3. Our simplified development methodology: Plan -> Code and Test -> Document.

We’ve broken down a large problem (game of “Rock, Paper, Scissors”) into more manageable and smaller programming problems, computer player, human player, comparison, game statistics, and using a loop. We solved each smaller programming problem and, in doing so, created a delightful game of “Rock, Paper, Scissors”. This is what professional programmers do on a daily basis.

With your potentially first coding experience, you’re now ready to enjoy your exciting new coding journey!

Naoise Gaffney, Code Institute Graduate

Learn coding basics for free

While the information above assumes that you will already have some coding abilities, don’t fret if it’s all new to you. Our free 5 Day Coding Challenge will teach you the basics of HTMLCSS and JavaScript. After just one hour a day over the five days, you’ll build your first ever webpage. Register now through the form below.

Best Way To Make Time To Study

Learning is a continuous process. Learning something new is never too late or too early, and when it comes to programming, the process of learning is simply endless. Every now and then, something new emerges in the tech sector, and to be the perfect programmer, you must be well-versed in the most recent concepts and […]

Python Cheat Sheet

Python is one of the most popular programming languages. It currently takes first place both in the Tiobe index and the PYPL index and has been named Language of the Year in 2007, 2010, 2018, 2020, and 2021. This popularity stems both from Python’s versatility and ease of use. Python can be used for Web […]

Git Stash

Git Stash is a built-in command that temporarily stores all of the most recent modifications to the code. That is, the modifications are stored, and the code is reset to its previous state. Git is software that allows a group of developers to keep track of changes and alterations to a source code throughout the […]