Here are 3 corrections. Instead of manually converting r,s,p
and 1,2,3
, use a dictionary. Instead of using a random number for the computers choice, use the players options. Instead of having extra win/lose/tie
checks, have one per outcome.
Fix Conversion
This is a simple way to convert r,p,s
into a name or a value:
options['r']['name'] == 'Rock'
options['r']['value'] == 1
options = {
'r':{'name':'Rock','value':1},
'p':{'name':'Paper','value':2},
's':{'name':'Scissors','value':3}
}
Fix Computer's Choice
By choosing a random key from options prevents having to hard-code values. It also allows us to lookup the name and value for the computer's choice. compChoice
will be r, p, or s
since those are options' keys.
compChoice = random.choice(list(options.keys()))
Fix win/lose/tie
Checks
A tie only happens if compValue==userValue
. Now consider +1 mod 3, for any value if you "+1 mod 3" you will get the only value that can beat it:
rocVal+1 %3 == papVal
papVal+1 %3 == sciVal
sciVal+1 %3 == rocVal
compVal = options[compChoice]['value']
userVal = options[userChoice]['value']
result = 'win'
if userVal == compVal: result = 'tie'
elif userVal+1 % 3 == compVal: result = 'lose'
# else: result = 'win'
print('You '+result+' against the computer!\n')
Advanced Check
But what if you want to play Rock-Paper-Scissors-Lizard-Spock? Or a any version with more than 3 options? If that is the case, here is a scalable solution from sch. Note that the number of options should always be odd. This way each element has the same number of superiors and inferiors.
Explanation: the key piece here is the decider. We want the difference between the two choices to be greater than or equal to 0
so we have to add numOpns
to it. Now picture these options as being on a circle (e.g. an analog clock). decider is the clockwise distance from b
to a
. [Note: if this distance is even, then the distance from a
to b
is odd] For any particular option, half of the remaining options are an even distance and half are an odd distance. Here we arbitrary choose that odd distances correspond to a loss.
compVal = options[compChoice]['value']
userVal = options[userChoice]['value']
numOpns = len(options)
decider = (numOpns+userVal-compVal) % numOpns
result = 'win'
if decider == 0: result = 'tie'
elif decider%2 == 0: result = 'lose'
# else decider%2 == 1: result = 'win'
print('You '+result+' against the computer!\n')
In this case, hints are definitely a problem if hard coded. So here is a fix for that:
for k,v in options.iteritems():
print(k.upper()+" or "+k+" for "+v['name'])
print('Q or q to quit')
And while we are at it, here is a options dictionary that simulates the correct Rock-Paper-Scissors-Lizard-Spock relationship.
options = {
'r':{'name':'Rock','value':5},
'l':{'name':'Lizard','value':4},
'o':{'name':'Spock','value':3},
's':{'name':'Scissors','value':2},
'p':{'name':'Paper','value':1}
}