This is something I wrote as a reply to a deleted "Rock/paper/scissors [updated]" question. Since I can't post it as an answer (and the line-by-line analysis is gone as well), it might be nice to get a code review.
"""A game of rock/paper/scissors."""
import random
SIGNS = ("rock", "paper", "scissors")
VERBS = ("crushes", "covers", "cut")
YES = ("yes", "y")
class Counter(object):
"""Keep track of game session scores."""
def __init__(self):
self.rounds = 0
self.losses = 0
self.wins = 0
self.draws = 0
self.rounds_total = 0
self.losses_total = 0
self.wins_total = 0
self.draws_total = 0
def increment(self, state):
"""Increment losses, wins, draws.
Args:
state: "losses", "wins", or "draws".
Raises:
ValueError: If input is invalid.
"""
if state not in ["losses", "wins", "draws"]:
raise ValueError("Acceptable input: losses, wins, or draws.")
for attr in (state, "%s_total" % state, "rounds", "rounds_total"):
setattr(self, attr, getattr(self, attr) + 1)
def flush(self):
"""Restart the current game counters, keep the total counters."""
self.rounds = 0
self.losses = 0
self.wins = 0
self.draws = 0
def print_results(self):
print "Games played: ", self.rounds
print "Games won: ", self.wins
print "Games lost: ", self.losses
print "Games drawn: ", self.draws
print "Total played: ", self.rounds_total
print "Total won: ", self.wins_total
print "Total lost: ", self.losses_total
print "Total drawn: ", self.draws_total
class Sign(object):
"""A rock/paper/scissors sign."""
def __init__(self, sign):
global SIGNS
if sign not in SIGNS:
raise ValueError("Allowed signs are: %s." % SIGNS.join(", "))
self.sign = sign
def __eq__(self, other):
try:
if self.sign == other.sign:
return True
except AttributeError:
pass
return False
def __gt__(self, other):
if (self.sign == "rock" and other.sign == "scissors" or
self.sign == "scissors" and other.sign == "paper" or
self.sign == "paper" and other.sign == "rock"):
return True
return False
def __lt__(self, other):
return not self.__gt__(other)
def main(max_rounds=5):
global SIGNS
global VERBS
global YES
counter = Counter()
while True:
if counter.rounds == max_rounds:
counter.print_results()
again = raw_input("Play/again? (Y/n) ").lower()
if again in YES:
counter.flush()
else:
print "Bye!"
break
while True:
player_sign = raw_input("Rock/paper/scissors? ").lower()
if player_sign not in SIGNS:
print "Only following words are valid: %s." % SIGNS.join(" ,")
continue
break
player = Sign(player_sign)
computer = Sign(random.choice(SIGNS))
if player > computer:
counter.increment("wins")
verb = VERBS[SIGNS.index(player.sign)]
print "Player wins: %s %s %s." % (player.sign, verb, computer.sign)
elif player == computer:
counter.increment("draws")
print "It's a draw! Both played %s." % player.sign
else:
counter.increment("losses")
verb = VERBS[SIGNS.index(computer.sign)]
print "Player lost: %s %s %s." % (computer.sign, verb, player.sign)
if __name__ == "__main__":
main(max_rounds=5)
__str__
forprint_results
and returning a string. Then you can use the built inprint
with a counter. \$\endgroup\$