[Tutor] more rps

Alan Gauld alan.gauld at freenet.co.uk
Tue Aug 15 18:49:07 CEST 2006


Let me start by saying that your code is pretty 
much OK as is. Indeed even using clssses for an 
RPS game is probably overkill to some extent.

What follows should be seen more as some ideas 
for experimentation and building towards a more 
flexible/expandable architecture for future 
projects. Its really about introducing some 
alternative approaches and increasing consistency.
It is definitely not "better" - and indeed could 
definitely be improved in several ways.

> class Human:
>   def __init__(self):
>     self.points = 0
>     self.choice = " "
> 
>   def plays(self):
>     fromUser = raw_input("Pick (R)ock, (P)aper, or
>               (S)cissors! ")
>     translate = {'r':'rock', 's':'scissors',
>               'p':'paper'} 
>     try:
>        self.choice = translate[fromUser.lower()]
>     except KeyError:
>        print 'Invalid Response'
> 
> class Computer:
>    def __init__(self):
>      self.points = 0
>      self.choice = " "
> 
>   def plays(self):
>     comp_choice = random.randint(0,2)
>     if comp_choice == 0:
>        self.choice = 'rock'
>     elif comp_choice == 1:
>        self.choice = 'paper'
>     else:
>       self.choice = 'scissors'

While its of little real advantage for this program 
I'd be tempted to introduce a Player superclass to avoid 
code duplication. The protocol of both classes 
here is the same and they both pass the "is-a" 
test for inheritance - ie. they are both Players.

class Player:
   def __init__(self):
     self.points = 0
     self.choice = " "

   def getChoice(self): pass   # implemented in subclass

   def plays(self):
     choice = self.getChoice()
     if choice == 0:
        self.choice = 'rock'
     elif choice == 1:
        self.choice = 'paper'
     else:
       self.choice = 'scissors'

Notice I put the plays function in the Player class.
By unifying the representation of choice we can use 
that function for both and just implement a 
relatively simple getChoice method in each subclass 
and we are done... (In fact we could simplify still 
further by storing the choice in its numeric form 
and using a class level dictionary to translate 
that to a string for printing - although in fact 
you never print what the choices were - maybe you 
should?)


class Human(Player):
   def getChoice(self):
      choice = raw_input('Choice - rps: ').lower()
      if choice in 'rps':
         return {'r':0,'p':1,'s':2}[choice]
      else: raise ValueError

class Computer(Player):
  def getChoice(self):
      return randrange(0,3)


> 
> def compare_objects(human, computer):
>   print "Human picked ", human.choice
>   print "Computer picked", computer.choice
>   results = { 'rock' : {'rock' : 'draw', 'paper': 0,
>                  'scissors': 1},
>                  'paper' : {'rock' : 1, 'paper': 'draw', 'scissors':
>                   0},
>                  'scissors' : {'rock' : 0, 'paper' : 1, 'scissors' :
>                  'draw'}
>              }
> 
>   outcome = results[human.choice][computer.choice]
>   if outcome == 0:
>     print "Computer Wins!"
>     computer.points = computer.points + 1
>   elif outcome == 1:
>     print "Human Wins!"
>     human.points = human.points + 1
>   else:
>     print "Draw!"

By using the number format of storage and the 
dictionary in the class you can simplify that
as in show below using lists.

> I actually figured out how to build the 2x2 matrix. 
> I'm quite proud of this.  

A nested dictionary is one way. Another is to use numbers 
to represent the choices and outcomes and create a nested 
list structure nested list

rps = {0:'Rock',1:'Paper',2:'Scissors'}
draw,loss,win = 0,1,2
outcomes = [ [0,1,2], [2,0,1], [1,2,0] ]

computer = randrange(0,3)
human = randrange(0,3)
result = outcomes[computer][human] 
if result == draw: print 'Draw'
elif result == loss: print 'Computer lost with', rps[computer]
elif result == win: print 'Computer won with', rps[computer]

The dictionary is more verbose but does have more readable
code.

I hope somebody finds at least some of that interesting! :-)
I guess what I'm really trying to show is how 
choosing different data structures makes a big 
difference to how the code looks.

Alan G.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.python.org/pipermail/tutor/attachments/20060815/d33a8c99/attachment.html 


More information about the Tutor mailing list