This is kind of out there, but you might find it interesting. This code does not make a Rock/Paper/Scissors game, instead is a tool for creating R/P?S type games where you create a game by defining the game rules. The Game class is used to make a single player Rock/Paper/Scissors/Lizard/Spock game and a two player Rock/Paper/Scissors game.
import random
class Player:
"""A human player"""
def __init__(self, plays, name=None):
self.name = "Player" if name is None else name
self.plays = {play.abbr:play for play in plays}
prefix = "Select" if name is None else f"{name} select"
self.prompt = f"{prefix} {', '.join([play.menu_name for play in plays])}: "
def choice(self):
"""Get player choice"""
while True:
play = input(self.prompt).upper()
if play in self.plays:
return self.plays[play]
print(f"{play} is not a valid selection")
class Computer:
"""A computer player"""
def __init__(self, plays, name="Computer"):
self.name = name
self.plays = plays
def choice(self):
"""Get player choice"""
return random.choice(self.plays)
class Play:
"""A play in a Rock/Paper/Scissor type game"""
abbreviations = [] # Keep track of abbreviations. Must be unique for all plays in a game.
def __init__(self, name):
for index, abbr in enumerate(name):
if abbr not in self.abbreviations:
self.abbreviations.append(abbr)
break
self.name = name
self.abbr = abbr
self.menu_name = f"{name[:index]}({name[index]}){name[index+1:]}"
self.rules = {}
def add_rule(self, loser, rule):
"""Add a rule that affects me"""
self.rules[loser] = rule
def beats(self, other):
"""Return rule if I beat other, else None"""
if other.name in self.rules:
return self.rules[other.name]
return None
class Game:
"""
A Rock/Paper/Scissor type game. I create a game based on a list of Rules
in the form: MOVE_A defeats MOVE_B
"""
def __init__(self, rules):
Play.abbreviations = []
self.plays = {}
self.abbr = {}
# Create plays. Rules start and end with a play name.
for rule in rules:
words = rule.split()
winner = words[0]
loser = words[-1]
if winner not in self.plays:
self.plays[winner] = play = Play(winner)
self.abbr[play.abbr] = play
self.plays[winner].add_rule(loser, rule)
def play(self, rounds=1, p1=None, p2=None):
"""Play the game.
Use rounds to set how many rounds are played. Default to 1
Use p1 to set player 1 name. If None, player name is "Player".
Use p2 to set select player 2 type. If None, player 2 is Computer, else Player(p1)"""
plays = list(self.plays.values())
player = [Player(plays, p1), Computer(plays) if p2 is None else Player(plays, p2)]
results = {
player[0].name: 0,
player[1].name: 0,
"Draw":0
}
# Play game
for _ in range(rounds):
play = [p.choice() for p in player]
print(f"{player[0].name} selects {play[0].name}, {player[1].name} selects {play[1].name}. ", end="")
if (rule := play[0].beats(play[1])):
print(f"{player[0].name} wins! {rule}\n")
results[player[0].name] += 1
elif (rule := play[1].beats(play[0])):
print(f"{player[1].name} wins! {rule}\n")
results[player[1].name] += 1
else:
print("Draw\n")
results["Draw"] += 1
print("\nResults")
for name, count in results.items():
print(f"{name:10} : {count}")
# Single player Rock/Paper/Scissors/Lizard/Spock game
Game([
"ROCK crushes SCISSORS",
"ROCK crushes LIZARD",
"PAPER covers ROCK",
"PAPER disproves SPOCK",
"SCISSORS cuts PAPER",
"SCISSORS decapitates LIZARD",
"LIZARD eats PAPER",
"LIZARD poisons SPOCK",
"SPOCK smashes SCISSORS",
"SPOCK vaporizes ROCK",
]).play(3)
# Bert and Ernie play Rock/Paper/Scissors
Game(["ROCK crushes SCISSORS", "PAPER covers ROCK", "SCISSORS cuts PAPER"]).play(3, "Bert", "Ernie")
The most interesting part for you might be how the code separates getting user input from game play. Here it is done so you can make single player or double player games, but it would be useful for something like your game. Also notice how little code is required to actually play the game. Determining the winner or a draw is only 3 lines of code!
Somewhere between writing very specific code like this:
if Player == "R":
print ("ROCK vs...")
elif Player == "P":
print ("PAPER vs...")
elif Player == "S":
print ("SCISSOR vs...")
And generic code like this:
Game(["ROCK crushes SCISSORS", "PAPER covers ROCK", "SCISSORS cuts PAPER"]).play(3, "Bert", "Ernie")
Is an appropriate balance point for a simple program like Rock/Paper/Scissors.