I have posted my first [version](http://codereview.stackexchange.com/questions/109813/rock-paper-scissors-with-scores-and-save-file) of RockPaperScissors a while back. It was on an old version of python with improper use of some functions. This version was updated to a more recent version of python and has a little extra for users who run on terminal. Is there anything I should add or change? Are my classes used correctly? Are there any bugs? Any overall improvements? # Programmer: DeliriousSyntax # Date: October 30, 2015 # File: RockPaperScissorsV2-py3.py # This is a classic game of rock paper scissors. import random import shelve import time import colorama import sys class Scorecard(dict): """Stores all items related to "Score\"""" def __init__(self, **kwargs): """Makes all values set to 0""" super().__init__(**kwargs) for key in ('rounds', 'losses', 'wins', 'draws', 'games_won', 'games_lost', 'games_played', "total_rounds", 'rounds_won', 'rounds_lost', 'rounds_tied', 'game_draws'): self[key] = 0 def reset(self): """Resets the scores for next game""" for key in ('rounds', 'losses', 'wins', 'draws'): self[key] = 0 def round_update(self, result): """Updates the info for each round :param result: """ self['rounds'] += 1 if result == 'win': self['wins'] += 1 elif result == 'loss': self['losses'] += 1 else: self['draws'] += 1 def add2score(self): """Adds the scores from the game to total scores""" self['games_played'] += 1 self['rounds_lost'] += self['losses'] self['rounds_won'] += self['wins'] self['rounds_tied'] += self['draws'] self['total_rounds'] += self['rounds'] if self['losses'] > self['wins']: self['games_lost'] += 1 elif self['losses'] < self['wins']: self['games_won'] += 1 else: self['game_draws'] += 1 def stats_board(self): """Returns the stat board""" return ('\n\n++++++++++++++++++++-=Stats=-++++++++++++++++++++++\n' '===================================================\n' '|--{:^11}--|--{:^12}--|--{:^12}--|\n'.format("X ", "Rounds", "Games") + '|--{:^11}--|--{:^12}--|--{:^12}--|\n'.format("Wins ", self['rounds_won'], self['games_won']) + '|--{:^11}--|--{:^12}--|--{:^12}--|\n'.format("Losses", self['rounds_lost'], self['games_lost']) + '|--{:^11}--|--{:^12}--|--{:^12}--|\n'.format("Draws ", self['rounds_tied'], self['game_draws']) + '|--{:^11}--|--{:^12}--|--{:^12}--|\n'.format("Played", self['total_rounds'], self['games_played']) + '\n') def final_score(self): """Returns the games final board""" return ('\n\n+++++++++++Final Score++++++++++++\n' '==================================\n' '|--{:^11}--|--{:^12}--|\n'.format('Wins ', self['wins']) + '|--{:^11}--|--{:^12}--|\n'.format('Losses', self['losses']) + '|--{:^11}--|--{:^12}--|\n'.format('Draws ', self['draws']) + '|--{:^11}--|--{:^12}--|\n'.format('Rounds', self['rounds']) + '\n') class Game: """Main Game Class""" MOVES = ('rock', 'paper', 'scissors') ROUND_OPTIONS = ('1', '3', '5', '7') MENU = ('stats', 'play', 'quit') WIN_CONDITIONS = { "rock": "scissors", "scissors": "paper", "paper": "rock", } green = colorama.Fore.GREEN yellow = colorama.Fore.YELLOW cyan = colorama.Fore.CYAN blue = colorama.Fore.BLUE magenta = colorama.Fore.MAGENTA COLORS = (green, yellow, cyan, blue, magenta) def delirioussyntax(self): """Creator""" colorama.init() idle = "idlelib" in sys.modules time.sleep(.3) if idle is False: print(colorama.Back.BLACK + colorama.Style.BRIGHT, end='') for letter in "Delirious": if idle is False: print(random.choice(Game.COLORS), end='') print(letter, end='') sys.stdout.flush() time.sleep(random.uniform(.1, .4)) if idle is False: print(colorama.Fore.RED, end='') for letter in "Syntax": print(letter, end='') sys.stdout.flush() time.sleep(random.uniform(.1, .4)) print(colorama.Style.RESET_ALL, "\n\n") def intro(self): """Intro statements""" self.Score = Scorecard() try: with shelve.open("RPSv2.dat") as f: self.Score = f["statistics"] except KeyError: with shelve.open("RPSv2.dat") as f: f["statistics"] = self.Score print("Brought to you by: ", end='') sys.stdout.flush() self.delirioussyntax() time.sleep(1) print("Welcome to the greatest, mind blowing challenge of all time.") print(" - Rock, Paper, Scissors!\n") print("Many have tried and many have FAILED...") print("This will be a test between the human mind and my AI.") input("Press \"enter\" when you believe your ready for this challenge.\n") print("\nGood Luck... Human.\n\n") def custom_input(self, question, choices): """A custom loop that checks to see if choices are valid :param choices: :param question: """ response = None while True: while response not in choices: response = input(question).lower() if response in choices: return response print("Correct inputs:\n >", end='') print("\n >".join(choices), "\n") def start_game(self): """Main menu of game basically""" self.intro() while True: choice = self.custom_input("Would you like to play, look at stats, or quit?:\n ->", self.MENU) if choice == 'play': self.play_game() elif choice == 'stats': stats = self.Score.stats_board() print(stats) else: break def computer_choice_gen(self): """Generates computer choice""" return random.choice(Game.MOVES) def play_game(self): """Player vs Computer game""" rounds = int(self.custom_input("\nHow many rounds would you like to play?\n ->", self.ROUND_OPTIONS)) while self.Score['rounds'] != rounds: self.user_choice = self.custom_input("\nWhat is your choice, human?\n ->", self.MOVES) self.computer_choice = self.computer_choice_gen() print("\nComputer choice is {}".format(self.computer_choice)) result = self.evaluate() self.Score.round_update(result) if result == "win": print("{} beats {}! The human wins this round.\n\n".format(self.user_choice, self.computer_choice)) elif result == "loss": print("{} beats {}! Hahaha! You lost this round!\n\n".format(self.computer_choice, self.user_choice)) else: print("I knew you were going to pick {}!\n\n".format(self.user_choice)) print(self.Score.final_score()) self.Score.add2score() self.Score.reset() with shelve.open("RPSv2.dat") as f: f["statistics"] = self.Score def evaluate(self): """returns if outcome of round""" if Game.WIN_CONDITIONS[self.user_choice] == self.computer_choice: return "win" elif self.user_choice == self.computer_choice: return "draw" else: return "loss" if __name__ == "__main__": Game = Game() Game.start_game()