Python Programming Primer

Rock Paper Scissors


To end the primer, let’s take a look at how a game of Rock Paper Scissors could be implemented in Python. We’ll start with a simple version and then add some more complexity to it. In addition to what we have looked into so far, the example uses functions input that is used to ask input from the user, lower that is used to lowercase a string, and a specific style of formatting outputs.

Version 1

The first version of a rock paper scissors could be a single-turn game where the user and the computer chooses a move, and the winner is determined based on the rules of the game. The computer picks a move randomly out of given options.

The game could look as follows.

import random

valid_options = ["rock", "paper", "scissors"]

def get_user_choice():
    print("Enter your choice out of",  valid_options)
    user_choice = input().lower()
    while user_choice not in valid_options:
        print("Invalid choice. Please enter one of", valid_options)
        user_choice = input().lower()
    return user_choice

def get_computer_choice():
    return random.choice(valid_options)

def determine_winner(user_choice, computer_choice):
    if user_choice == computer_choice:
        return "It's a tie!"
    if user_choice == "rock":
        return "You win!" if computer_choice == "scissors" else "Computer wins!"
    if user_choice == "paper":
        return "You win!" if computer_choice == "rock" else "Computer wins!"
    if user_choice == "scissors":
        return "You win!" if computer_choice == "paper" else "Computer wins!"

def play_game():
    user_choice = get_user_choice()
    computer_choice = get_computer_choice()
    print(f"You chose {user_choice}.")
    print(f"Computer chose {computer_choice}.")
    print(determine_winner(user_choice, computer_choice))

if __name__ == "__main__":
    play_game()

When you run the game locally in your programming environment, it should look something like this.

Enter your choice out of ['rock', 'paper', 'scissors']
rock
You chose rock.
Computer chose paper.
Computer wins!

The functionality of the program is quite simple. First, the user is asked to enter a choice, after which a computer picks a random choice. The winner is determined based on the rules of the game.

Version 2

A next step could be to encapsulate the game into a class.

import random

class RockPaperScissors:
  def __init__(self):
    self.valid_options = ["rock", "paper", "scissors"]

  def get_user_choice(self):
    print("Enter your choice out of", self.valid_options)
    user_choice = input().lower()
    while user_choice not in self.valid_options:
      print("Invalid choice. Please enter one of", self.valid_options)
      user_choice = input().lower()
    return user_choice

  def get_computer_choice(self):
    return random.choice(self.valid_options)

  def determine_winner(self, user_choice, computer_choice):
    if user_choice == computer_choice:
      return "It's a tie!"
    if user_choice == "rock":
      return "You win!" if computer_choice == "scissors" else "Computer wins!"
    if user_choice == "paper":
      return "You win!" if computer_choice == "rock" else "Computer wins!"
    if user_choice == "scissors":
      return "You win!" if computer_choice == "paper" else "Computer wins!"

  def play_game(self):
    user_choice = self.get_user_choice()
    computer_choice = self.get_computer_choice()
    print(f"You chose {user_choice}.")
    print(f"Computer chose {computer_choice}.")
    print(self.determine_winner(user_choice, computer_choice))

if __name__ == "__main__":
  game = RockPaperScissors()
  game.play_game()

The functionality of the game remains the same, but the game is now encapsulated into a class. This makes it a bit easier to plug in functionality from other locations.

Version 3

Let’s next create an AI and plug it into the game. Our first AI will be a simple one that always plays the same move.

class RockPaperScissorsAI:
  def __init__(self, move):
    self.move = move

  def get_move(self):
    return self.move

We can then plug the AI into the game as follows, injecting it through the constructor and using it to pick the move of the computer.

import random

class RockPaperScissors:
  def __init__(self, ai):
    self.ai = ai
    self.valid_options = ["rock", "paper", "scissors"]

  def get_user_choice(self):
    print("Enter your choice out of", self.valid_options)
    user_choice = input().lower()
    while user_choice not in self.valid_options:
      print("Invalid choice. Please enter one of", self.valid_options)
      user_choice = input().lower()
    return user_choice

  def get_computer_choice(self):
    return self.ai.get_move()

  def determine_winner(self, user_choice, computer_choice):
    if user_choice == computer_choice:
      return "It's a tie!"
    if user_choice == "rock":
      return "You win!" if computer_choice == "scissors" else "Computer wins!"
    if user_choice == "paper":
      return "You win!" if computer_choice == "rock" else "Computer wins!"
    if user_choice == "scissors":
      return "You win!" if computer_choice == "paper" else "Computer wins!"

  def play_game(self):
    user_choice = self.get_user_choice()
    computer_choice = self.get_computer_choice()
    print(f"You chose {user_choice}.")
    print(f"Computer chose {computer_choice}.")
    print(self.determine_winner(user_choice, computer_choice))

if __name__ == "__main__":
  edward_scissorhands = RockPaperScissorsAI("scissors")
  game = RockPaperScissors(edward_scissorhands)
  game.play_game()
Enter your choice out of ['rock', 'paper', 'scissors']
rock
You chose rock.
Computer chose scissors.
You win!

Version 4

Let’s adjust the AI and the program a bit so that the AI is given information about the user’s previous move. The AI will then use this information to determine its next move. At the beginning, the AI is given a move that it believes that the player previously chose.

class RockPaperScissorsAI:
  def __init__(self, initial_player_move):
    self.player_move = initial_player_move

  def get_move(self):
    # ???

  def player_chose(self, move):
    self.player_move = move

In the above version, the AI doesn’t know how to use the player’s move. Let’s add some logic to the AI so that it can use the information to determine its next move. In the following, the AI will always play the move that beats the player’s previous move.

class RockPaperScissorsAI:
  def __init__(self, initial_player_move):
    self.player_move = initial_player_move

  def get_move(self):
    if self.player_move == "rock":
      return "paper"
    if self.player_move == "paper":
      return "scissors"
    if self.player_move == "scissors":
      return "rock"

  def player_chose(self, move):
    self.player_move = move

We also have to adjust the rock paper scissors game accordingly so that the AI is given information of the player’s choice. The key change is in the play_game method, where the AI is given the player’s at the end.

# ...
  def play_game(self):
    user_choice = self.get_user_choice()
    computer_choice = self.get_computer_choice()
    print(f"You chose {user_choice}.")
    print(f"Computer chose {computer_choice}.")
    print(self.determine_winner(user_choice, computer_choice))

    self.ai.player_chose(user_choice)
# ...

Now, the AI will always play the move that beats the player’s previous move.

Enter your choice out of ['rock', 'paper', 'scissors']
rock
You chose rock.
Computer chose rock.
It's a tie!

However, as the game lasts just one round, the AI doesn’t have much information to go on. Let’s adjust the game so that we can provide the number of rounds that it lasts. Let’s again adjust the play_game method, this time providing the number of rounds as a parameter, and running the game for the given number of rounds.

# ...
  def play_game(self, rounds):
    for i in range(rounds):
      user_choice = self.get_user_choice()
      computer_choice = self.get_computer_choice()
      print(f"You chose {user_choice}.")
      print(f"Computer chose {computer_choice}.")
      print(self.determine_winner(user_choice, computer_choice))

      self.ai.player_chose(user_choice)
# ...

Now, also the call to the game has to be adjusted accordingly.

# ...
if __name__ == "__main__":
  ai = RockPaperScissorsAI("scissors")
  game = RockPaperScissors(ai)
  game.play_game(3)
Enter your choice out of ['rock', 'paper', 'scissors']
rock
You chose rock.
Computer chose rock.
It's a tie!
Enter your choice out of ['rock', 'paper', 'scissors']
rock
You chose rock.
Computer chose paper.
Computer wins!
Enter your choice out of ['rock', 'paper', 'scissors']
rock
You chose rock.
Computer chose paper.
Computer wins!

Version 5

Let’s further adjust the AI so that it doesn’t always play the same move. Instead, it will play the move that beats the player’s previous move with a probability of 50%. The remaining 50% of the time, it will play a random move.

import random

class RockPaperScissorsAI:
  def __init__(self, initial_player_move):
    self.player_move = initial_player_move

  def get_move(self):
    rnd = random.random()

    if rnd < 0.5:
      return random.choice(["rock", "paper", "scissors"])

    if self.player_move == "rock":
      return "paper"
    if self.player_move == "paper":
      return "scissors"
    if self.player_move == "scissors":
      return "rock"

  def player_chose(self, move):
    self.player_move = move

Now, the AI has some randomness to it and it is no longer as easy to beat as previously.

Enter your choice out of ['rock', 'paper', 'scissors']
rock
You chose rock.
Computer chose rock.
It's a tie!
Enter your choice out of ['rock', 'paper', 'scissors']
paper
You chose paper.
Computer chose paper.
It's a tie!
Enter your choice out of ['rock', 'paper', 'scissors']
paper
You chose paper.
Computer chose scissors.
Computer wins!

Version 6

Let’s further adjust the AI so that it keeps track of all the prior moves of the player. It will then use this information to determine its next move. In addition, the AI also will have a name.

class RockPaperScissorsAI:
  def __init__(self):
    self.player_moves = []

  def get_move(self):
    if len(self.player_moves) == 0:
        return random.choice(["rock", "paper", "scissors"])

    last_move = self.player_moves[-1]

    if last_move == "rock":
      return "paper"
    if last_move == "paper":
      return "scissors"
    if last_move == "scissors":
      return "rock"

  def get_name(self):
    return "Bot botiti bot bot bot"

  def player_chose(self, move):
    self.player_moves.append(move)

The game has to be adjusted accordingly so that the AI is given a name and the game prints the name of the AI when it makes a move. As a whole, the game looks as follows.

class RockPaperScissors:
  def __init__(self, ai):
    self.ai = ai
    self.valid_options = ["rock", "paper", "scissors"]

  def get_user_choice(self):
    print("Enter your choice out of", self.valid_options)
    user_choice = input().lower()
    while user_choice not in self.valid_options:
      print("Invalid choice. Please enter one of", self.valid_options)
      user_choice = input().lower()
    return user_choice

  def get_computer_choice(self):
    return self.ai.get_move()

  def determine_winner(self, user_choice, computer_choice):
    if user_choice == computer_choice:
      return "It's a tie!"
    if user_choice == "rock":
      return "You win!" if computer_choice == "scissors" else "Computer wins!"
    if user_choice == "paper":
      return "You win!" if computer_choice == "rock" else "Computer wins!"
    if user_choice == "scissors":
      return "You win!" if computer_choice == "paper" else "Computer wins!"

  def play_game(self, rounds):
    for i in range(rounds):
      user_choice = self.get_user_choice()
      computer_choice = self.get_computer_choice()
      computer_name = self.ai.get_name()
      print(f"You chose {user_choice}.")
      print(f"{computer_name} chose {computer_choice}.")
      print(self.determine_winner(user_choice, computer_choice))

      self.ai.player_chose(user_choice)

if __name__ == "__main__":
  ai = RockPaperScissorsAI()
  game = RockPaperScissors(ai)
  game.play_game(3)

Now, playing the game would look as follows.

Enter your choice out of ['rock', 'paper', 'scissors']
rock
You chose rock.
Bot botiti bot bot bot chose rock.
It's a tie!
Enter your choice out of ['rock', 'paper', 'scissors']
rock
You chose rock.
Bot botiti bot bot bot chose paper.
Computer wins!
Enter your choice out of ['rock', 'paper', 'scissors']
rock
You chose rock.
Bot botiti bot bot bot chose paper.
Computer wins!

Loading Exercise...